Data
env_sort <- read.csv(file.path(dataPath,"inputs/NSenv_sort_2022-09-22.csv")) %>% as.data.frame
otu_sort <- read.csv(file.path(dataPath,"inputs/NSotu_sort_2022-09-22.csv")) %>% as.data.frame
table(env_sort$SampID2 == otu_sort$SampID)
#must be same length and equal to unique sample number length - the ordered lists are assumed to be directly relatable on a row by row basis
dim(env_sort)
dim(otu_sort)
remove any variables with not enough coverage
env_sort <- env_sort %>% select(-c("BO22_lightbotmean_bdmean",
"BO22_lightbotltmax_bdmean",
"BO22_lightbotltmin_bdmean",
"BO22_lightbotrange_bdmean"))
Plot map to check location of samples
env_sort_locations<- ggplot(data = env_sort,
aes(x = X.y,
y = Y)) +
theme_classic() +
geom_point(aes(colour = bathy),
size = 2) +
scale_colour_gradient2(low = "red",
mid = "yellow",
high = "green") +
ggtitle("Location of samples in sorted env file")
env_sort_locations
Data cleaning
## Removing NAs
otuCompl <- otu_sort[complete.cases(env_sort[, -c(1:20)]), ]
envCompl <- env_sort[complete.cases(env_sort[, -c(1:20)]), ]
## Removing observations with less than 4 OTUs
sel <- rowSums(otuCompl[, -c(1:2)]) >= 4
otuSel <- otuCompl[sel, ]
envSel <- envCompl[sel, ]
## Removing phosphate
#envSel <- envSel %>% select(-phosphate_mean.tif)
dim(otuSel); dim(envSel)
Show what samples are left after complete cases and >4 OTUs filters
env_sel_locations<- ggplot(data = envSel,
aes(x = X.y,
y = Y)) +
theme_classic() +
geom_point(aes(colour = bathy),
size = 2) +
scale_colour_gradient2(low = "red",
mid = "yellow",
high = "green") +
ggtitle("Location of samples in sorted env file")
env_sel_locations
Show what got removed in complete cases filter
envCompl_ccrem<-env_sort%>%filter(!SampID%in%envCompl$SampID)
envCompl_ccrem_locations<- ggplot(data = envCompl_ccrem,
aes(x = X.y,
y = Y)) +
theme_classic() +
geom_point(aes(colour = bathy),
size = 2) +
scale_colour_gradient2(low = "red",
mid = "yellow",
high = "green") +
ggtitle("Location of removed complete case samples resulting in envSel file")
envCompl_ccrem_locations
Show what got removed in <4 OTUs filter
inv.sel <- rowSums(otuCompl[, -c(1:2)]) < 4
env.invSel <- envCompl[inv.sel, ]
env.invSel_locations<- ggplot(data = env.invSel,
aes(x = X.y,
y = Y)) +
theme_classic() +
geom_point(aes(colour = bathy),
size = 2) +
scale_colour_gradient2(low = "red",
mid = "yellow",
high = "green") +
ggtitle("Location of removed samples with <4 OTUs resulting in envSel file")
env.invSel_locations
[Optional] Data thinning
# otu_red <- otu1[1:500, ]
# otu <- otu_red
#
# env_red <- env[1:500, ]
# env <- env_red
Whole dataset for first run
otu<-otuSel[,-c(1)]
env<-envSel[, -c(1,3:23)]
table(is.na(otu))
table(is.na(env))
#str(otuSel)
#str(envSel)
Splitting in subsets
# ## Class 1
# otu1 <- subset(otuSel, envSel$SplitRev == 1)
# env1 <- envSel %>% filter(SplitRev == 1)
#
# ## Class 2
# otu2 <- subset(otuSel, envSel$SplitRev == 2)
# env2 <- envSel %>% filter(SplitRev == 2)
#
# ## Class 4
# otu3 <- subset(otuSel, envSel$SplitRev == 3)
# env3 <- envSel %>% filter(SplitRev == 3)
#
# ## Class 4
# otu4 <- subset(otuSel, envSel$SplitRev == 4)
# env4 <- envSel %>% filter(SplitRev == 4)
#
# ## Class 6
# otu6 <- subset(otuSel, envSel$SplitRev == 6)
# env6 <- envSel %>% filter(SplitRev == 6)
#
# ## Class 7
# otu7 <- subset(otuSel, envSel$SplitRev == 7)
# env7 <- envSel %>% filter(SplitRev == 7)
#
# ## Class 8
# otu8 <- subset(otuSel, envSel$SplitRev == 8)
# env8 <- envSel %>% filter(SplitRev == 8)
Abundance weighting
Make function You might have to drop variables that have been imported as character
otu_pa <- decostand(x = otu[, -c(1)],
method = "pa")
# y = ax^w # power transformation formula
dt <- otu[, -c(1:2)] # species data to transform
x_mn <- min(dt[dt > 0])
x_mx <- max(dt)
rng <- 6 # abundance range
w <- log(rng) / (log(x_mx) - log(x_mn))
a <- x_mn^(-w)
# otu_6 <- a * dt[, -c(1:3)]^w
otu_6 <- a * dt^w
range(otu_6)
Ordination methods
DCA PA
dca_pa <- decorana(veg = otu_pa)
print(dca_pa, head=T)
GNMDS PA
Distances - don’t run if loading saved object
## Bray-Curtis
dist_pa <- vegdist(x = otu_pa, method = "bray")
## Geodist
ep <- 0.8 # epsilon
geodist_pa <- isomapdist(dist = dist_pa, epsilon = ep)
Save the result - don’t run if loading saved object
saveRDS(geodist_pa,
file = (file.path(dataPath,"inputs/NSgeodist_pa.rds")))
Ordination
monoMDS - don’t run if loading saved object
takes 10 secs
Sys.time()
d <- 2
mds_pa <- list()
for (i in 1:100) {
mds_pa[[i]]<-monoMDS(geodist_pa,
matrix(c(runif(dim(otu_pa)[1]*d)),
nrow = dim(otu_pa)[1]),
k = d,
model = "global",
maxit = 2000,
smin = 1e-7,
sfgrmin = 1e-7)
}
Save the result - don’t run if loading saved object
saveRDS(mds_pa,
file = file.path(dataPath,"inputs/NSmds_pa.rds"))
Best nmds solution - PA
Make function?
# Loading geodist object
# geodist_nfi <- readRDS(file = "../SplitRev2_geodist_pa_full.rds")
# Loading mds results
# mds <- readRDS(file = "../SplitRev2_mds_pa_full.rds")
## Extracting the stress of each nmds iteration
mds_stress_pa<-unlist(lapply(mds_pa, function(v){v[[22]]}))
ordered_pa <-order(mds_stress_pa)
## Best, second best, and worst solution
mds_stress_pa[ordered_pa[1]]
mds_stress_pa[ordered_pa[2]]
mds_stress_pa[ordered_pa[10]]
## Scaling of axes to half change units and varimax rotation by postMDS
mds_best_pa<-postMDS(mds_pa[[ordered_pa[1]]],
geodist_pa,
pc = TRUE,
halfchange = TRUE,
threshold = ep) # Is this threshold related to the epsilon above?
mds_best_pa
mds_secbest_pa <- postMDS(mds_pa[[ordered_pa[2]]],
geodist_pa,
pc = TRUE,
halfchange = TRUE,
threshold = ep)
mds_secbest_pa
## Procrustes comparisons
procr_pa <- procrustes(mds_best_pa,
mds_secbest_pa,
permutations=999)
protest(mds_best_pa,
mds_secbest_pa,
permutations=999)
plot(procr_pa)
png(file=file.path(dataPath,"outputs/NSprocrustes_pa.png"), width=1000, height=700)
plot(procr_pa)
dev.off()
Correlation of axis: DCA vs NMDS - PA
# Extracting ordination axis
ax <- 2
axis_pa <- cbind(mds_best_pa$points,
scores(dca_pa,
display = "sites",
origin = TRUE)[, 1:ax])
ggcorr(axis_pa,
method=c("everything","kendall"),
label = TRUE,
label_size = 3,
label_color = "black",
nbreaks = 8,
label_round = 3,
low = "red",
mid = "white",
high = "green")
DCA R6
dca_r6 <- decorana(veg = otu_6)
print(dca_r6, head=T)
GNMDS R6
Distances - don’t run if loading saved object
## Bray-Curtis
dist_r6 <- vegdist(x = otu_6, method = "bray")
## Geodist
ep <- 0.80 # epsilon
geodist_r6 <- isomapdist(dist = dist_r6, epsilon = ep)
Save the result - don’t run if loading saved object
saveRDS(geodist_r6,
file = (file.path(dataPath,"inputs/NSgeodist_r6.rds")))
Ordination
200 reps - don’t run if loading saved object
took 20 secs
# monoMDS
d <- 2
mds_r6 <- list()
Sys.time()
for (i in 1:200) {
mds_r6[[i]]<-monoMDS(geodist_r6,
matrix(c(runif(dim(otu_6)[1]*d)),
nrow = dim(otu_6)[1]),
k = d,
model = "global",
maxit = 2000,
smin = 1e-7,
sfgrmin = 1e-7)
}
Sys.time()
Save the result - don’t run if loading saved object
saveRDS(mds_r6,
file = file.path(dataPath,"inputs/NSmds_r6.rds"))
Best nmds solution r6 200 rep
# Loading geodist object
# geodist_nfi <- readRDS(file = "../SplitRev2_geodist_nfi.rds")
# Loading mds results
# mds <- readRDS(file = "../SplitRev2_mds.rds")
## Extracting the stress of each nmds iteration
mds_stress_r6<-unlist(lapply(mds_r6, function(v){v[[22]]}))
ordered_r6 <-order(mds_stress_r6)
## Best, second best, and worst solution
mds_stress_r6[ordered_r6[1]]
mds_stress_r6[ordered_r6[2]]
mds_stress_r6[ordered_r6[100]]
## Scaling of axes to half change units and varimax rotation by postMDS
mds_best_r6<-postMDS(mds_r6[[ordered_r6[1]]],
geodist_r6,
pc = TRUE,
halfchange = TRUE,
threshold = ep) # Is this threshold related to the epsilon above?
mds_best_r6
mds_secbest_r6<-postMDS(mds_r6[[ordered_r6[2]]],
geodist_r6,
pc = TRUE,
halfchange = TRUE,
threshold = ep)
mds_secbest_r6
## Procrustes comparisons
procr_r6 <- procrustes(mds_best_r6,
mds_secbest_r6,
permutations=999)
protest(mds_best_r6,
mds_secbest_r6,
permutations=999)
plot(procr_r6)
png(file.path(dataPath,"outputs/NSprocrustes_r6.png"), width=1000, height=700,) #added 1000
plot(procr_r6)
dev.off()
#### 1000 reps - don’t run if loading saved object Currently commented out as it gained nothing but took extra time. Can be removed in due course.
Correlation of axis: DCA vs NMDS
retain the 200 rep version
# Extracting ordination axis
ax <- 2
axis_r6 <- cbind(mds_best_r6$points,
scores(dca_r6,
display = "sites",
origin = TRUE)[, 1:ax])
ggcorr(axis_r6,
method=c("everything","kendall"),
label = TRUE,
label_size = 3,
label_color = "black",
nbreaks = 8,
label_round = 3,
low = "red",
mid = "white",
high = "green")
Plotting DCA & GNMDS
## Adding scores to data frame
otu_6$gnmds1 <- mds_best_r6$points[, 1]
otu_6$gnmds2 <- mds_best_r6$points[, 2]
otu_6$dca1 <- scores(dca_r6, display = "sites", origin = TRUE)[, 1]
otu_6$dca2 <- scores(dca_r6, display = "sites", origin = TRUE)[, 2]
p_gnmds_r6 <- ggplot(data = otu_6,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
coord_fixed() +
ggtitle("GNMDS",
subtitle = "First run") +
geom_point(colour = "red") +
geom_vline(xintercept = 0,
linetype = 2,
colour = "lightgray") +
geom_hline(yintercept = 0,
linetype = 2,
colour = "lightgray")
p_dca_r6 <- ggplot(data = otu_6,
aes(x = dca1,
y = -dca2)) +
theme_classic() +
coord_fixed() +
ggtitle("DCA",
subtitle = "First run") +
geom_point(colour = "red") +
geom_vline(xintercept = 0,
linetype = 2,
colour = "lightgray") +
geom_hline(yintercept = 0,
linetype = 2,
colour = "lightgray")
p_gnmds_r6 + p_dca_r6
Species-environment relationships
Selecting ordination
ord <- mds_best_r6
## Axis scores if selected ord is GNMDS
axis <- ord$points %>% as.data.frame
## Axis scores if selected ord is DCA
# axis <- scores(ord,
# display = "sites",
# origin = TRUE)[, 1:ax])
Create additional variables
decided to make MLD-bathy vars
env<-env %>%
mutate ("MLDmean_bathy"=MLDmean_Robinson-(bathy*-1),
"MLDmin_bathy"=MLDmin_Robinson-(bathy*-1),
"MLDmax_bathy"=MLDmax_Robinson-(bathy*-1))
env$MLDmean_bathy<-cut(env$MLDmean_bathy,
breaks=c(-2560, -20,20,130),#checked range of values first (min -2554, max 123)
labels=c('belowMLD','onPycno','inMixLayer'))
env$MLDmin_bathy<-cut(env$MLDmin_bathy,
breaks=c(-2560, -20,20,130),#checked range of values first (min -2554, max 123)
labels=c('belowMLD','onPycno','inMixLayer'))
env$MLDmax_bathy<-cut(env$MLDmax_bathy,
breaks=c(-2560, -20,20,130),#checked range of values first (min -2554, max 123)
labels=c('belowMLD','onPycno','inMixLayer'))
env$swDensRob_avs<-swRho(salinity=env$Smean_Robinson,
temperature=env$Tmean_Robinson,
pressure=(env$bathy*-1),
eos="unesco")
Correlation ordination axes and environmental variables
Removing non-env vars
env_cont<-env%>% select(-c(landscape,sedclass,gmorph, MLDmean_bathy, MLDmax_bathy, MLDmin_bathy, #categorical
optional, #not a var
MLDmax_Robinson, MLDmean_Robinson, MLDmin_Robinson, #replaced by new vars
MLDsd_Robinson #not meaningful
))
env_cont<-env_cont%>% mutate_if(is.integer,as.numeric)
env_corr <- env_cont %>% select(-c(SampID))
# env_corr$coords.x1<-as.numeric(env_corr$coords.x1)
# env_corr$coords.x2<-as.numeric(env_corr$coords.x2)
env_corr[(!is.numeric(env_corr)),]
Correlations
# Vector to hold correlations
cor_ax1 <- NULL
cor_ax2 <- NULL
pv_ax1 <- NULL
pv_ax2 <- NULL
# NMDS1
for( i in seq(length(env_corr))) {
ct.i <- cor.test(axis$MDS1,
env_corr[, i],
method = "kendall")
cor_ax1[i] <- ct.i$estimate
pv_ax1[i] <- ct.i$p.value
}
# NMDS2
for( i in seq(length(env_corr))) {
ct.i <- cor.test(axis$MDS2,
env_corr[, i],
method = "kendall")
cor_ax2[i] <- ct.i$estimate
pv_ax2[i] <- ct.i$p.value
}
cor_tab <- data.frame(env = names(env_corr),
ord_ax1 = cor_ax1,
pval_ax1 = pv_ax1,
ord_ax2 = cor_ax2,
pval_ax2 = pv_ax2)
cor_tab
write.csv(x = cor_tab,
file = file.path(dataPath,"inputs/NScor-table_r6_200rep_MLD-bathy.csv"),
row.names = FALSE)
Dot chart to check for gaps in correlation
cor_a1_sort<-cor_tab%>%
mutate(abs_ord_ax1=abs(ord_ax1),
abs_ord_ax2=abs(ord_ax2)) %>%
arrange(desc(abs_ord_ax1))
cor_a2_sort<-cor_tab%>%
mutate(abs_ord_ax1=abs(ord_ax1),
abs_ord_ax2=abs(ord_ax2)) %>%
arrange(desc(abs_ord_ax2))
dotchart(cor_a1_sort$abs_ord_ax1, main="Absolute (+/-) correlations between envVars and gnmds axis 1")
cor_cut<-0.4 #decide
cor_sel<-subset(cor_a1_sort,abs_ord_ax1>cor_cut)
cor_sel
Sel env var (top corr)
env_os <- env[, cor_sel$env]
env_os
str(env_os)
Ordisurfs top corr
ordsrfs <- list(length = ncol(env_os))
for (i in seq(ncol(env_os))) {
os.i <- gg_ordisurf(ord = ord,
env.var = env_os[, i],
pt.size = 1,
# binwidth = 0.05,
var.label = names(env_os)[i],
gen.text.size = 10,
title.text.size = 15,
leg.text.size = 10)
ordsrfs[[i]] <- os.i$plot
}
ordsrfs_plt <- ggarrange(plotlist = ordsrfs,
nrow = 4,
ncol = 3)
ordsrfs_plt
Save some outputs
ggexport(ordsrfs_plt,
filename = file.path(dataPath,"outputs/NSordisurfs_top_corr.png"),
width = 1500,
height = 2000)
Sel env var (manual)
env_os_m <- env[,c("Tmean_Robinson", #top corr
"salt_max", #top corr
"Smax_Robinson", #comparison to top corr
"swDensRob_avs", #top corr
#"BO22_icecoverltmax_ss",#top corr ax2
# "BO22_icecovermean_ss",#top corr
"BO22_dissoxmean_bdmean",#top corr
#"BO22_carbonphytoltmin_bdmean",#top corr - no clear gradient in ordisurf
"BO22_ppltmin_ss", #top corr
"X.y", #comparison to Y
"Y", #top corr
"spd_std", #top corr ax2 (blended model)
"CSpdsd_Robinson", #comparison to top corr ax2 (blended model)
"mud", #highest sed var ax1 + corr
"gravel",#highest sed var ax1 - corr
"BO22_silicateltmax_bdmean", #just under top corr ax1
"bathy" #intuitive for comparisons
)]
env_os_m
str(env_os_m)
Ordisurfs top corr
ordsrfs_m <- list(length = ncol(env_os_m))
for (i in seq(ncol(env_os_m))) {
os.i_m <- gg_ordisurf(ord = ord,
env.var = env_os_m[, i],
pt.size = 1,
# binwidth = 0.05,
var.label = names(env_os_m)[i],
gen.text.size = 10,
title.text.size = 15,
leg.text.size = 10)
ordsrfs_m[[i]] <- os.i_m$plot
}
ordsrfs_plt_m <- ggarrange(plotlist = ordsrfs_m,
nrow = 4,
ncol = 4)
ordsrfs_plt_m
Save some outputs
ggexport(ordsrfs_plt_m,
filename = file.path(dataPath,"outputs/NSordisurfs_man_sel.png"),
width = 2000,
height = 2000)
Envfit
## Select if any var should be excluded from envfit (makes less busy to read)
env_os_m_envfit<-env_os_m [,c("Tmean_Robinson", #top corr
"salt_max", #top corr
"Smax_Robinson", #comparison to top corr
"swDensRob_avs", #top corr
# "BO22_icecoverltmax_ss",#top corr ax2
# "BO22_icecovermean_ss",#top corr
"BO22_dissoxmean_bdmean",#top corr
#"BO22_carbonphytoltmin_bdmean",#top corr - no clear gradient in ordisurf
# "BO22_ppltmin_ss", #top corr
"X.y", #comparison to Y
"Y", #top corr
# "spd_std", #top corr ax2 (blended model)
"CSpdsd_Robinson", #comparison to top corr ax2 (blended model)
"mud", #highest sed var ax1 + corr
"gravel",#highest sed var ax1 - corr
# "BO22_silicateltmax_bdmean", #just under top corr ax1
"bathy" #intuitive for comparisons
)]
colnames(env_os_m_envfit)<-c("T", #top corr
"Smx", #top corr
"SmaxR", #comparison to top corr
"swDensR", #top corr
# "icecovmax",#top corr ax2
# "icecovav",#top corr
"dissoxav",#top corr
#"BO22_carbonphytoltmin_bdmean",#top corr - no clear gradient in ordisurf
# "ppltmin", #top corr
"X", #comparison to Y
"Y", #top corr
#"spd_std", #top corr ax2 (blended model)
"CSpdsdR", #comparison to top corr ax2 (blended model)
"mud", #highest sed var ax1 + corr
"gravel",#highest sed var ax1 - corr
# "SiLtmax", #just under top corr ax1
"bathy" #intuitive for comparisons
)
## Envfot plot
gg_envfit(ord = ord,
env = env_os_m_envfit,
pt.size = 1)
## Envfit analysis
ef <- envfit(ord = ord,
env = env_os_m_envfit,
# na.rm = TRUE
)
efDF <- as.data.frame(scores(ef,
display = "vectors"))
Save the plot
ggsave(filename = file.path(dataPath,"outputs/NSEnvFit_man_sel_cln.png"),
device = "png",
dpi=300 )
Categorical envVar visualised on the mdsplots
use dataset with categorical var included
env_vis<-env
env_vis$gnmds1 <- otu_6$gnmds1
env_vis$gnmds2 <- otu_6$gnmds2
gnmds w mld mean - bathy
p_mld <- ggplot(data = env_vis,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
coord_fixed() +
ggtitle("GNMDS coloured by proximity to mixed layer depth",
subtitle = "First run") +
geom_point(aes(colour = MLDmean_bathy)) +
geom_vline(xintercept = 0,
linetype = 2,
colour = "lightgray") +
geom_hline(yintercept = 0,
linetype = 2,
colour = "lightgray")
p_mld
Save the plot
ggsave(filename = file.path(dataPath,"outputs/NSgnmds_MLDmeanBathy.png"),
device = "png",
dpi=300 )
gnmds w sedclass
deal with sedclass codes
env_vis<- env_vis %>%
mutate(
sedclassName = case_when(
sedclass == "1" ~ "SedCoverR",
sedclass == "5" ~ "Rock",
sedclass == "20" ~ "Mud",
sedclass == "21" ~ "MwBlock",
sedclass == "40" ~ "sMud",
sedclass == "80" ~ "mSand",
sedclass == "100" ~ "Sand",
sedclass == "110" ~ "gMud",
sedclass == "115" ~ "gsMud",
sedclass == "120" ~ "gmSand",
sedclass == "130" ~ "gSand",
sedclass == "150" ~ "MSG",
sedclass == "160" ~ "sGravel",
sedclass == "170" ~ "Gravel",
sedclass == "175" ~ "GravBlock",
sedclass == "185" ~ "SGBmix",
sedclass == "205" ~ "S/MwB",
sedclass == "206" ~ "S/MwG/B",
sedclass == "215" ~ "SGBalt",
sedclass == "300" ~ "HardSed",
sedclass == "500" ~ "Biogenic"
)
)
colour palette to cope with up to 25 categorical colours
c25 <- c(
"dodgerblue2", "#E31A1C", # red
"green4",
"#6A3D9A", # purple
"#FF7F00", # orange
"black", "gold1",
"skyblue2", "#FB9A99", # lt pink
"palegreen2",
"#CAB2D6", # lt purple
"#FDBF6F", # lt orange
"gray70", "khaki2",
"maroon", "orchid1", "deeppink1", "blue1", "steelblue4",
"darkturquoise", "green1", "yellow4", "yellow3",
"darkorange4", "brown"
)
p_sed <- ggplot(data = env_vis,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
coord_fixed() +
ggtitle("GNMDS coloured by sediment class",
subtitle = "First run") +
geom_point(aes(colour = factor(sedclassName))) +
scale_colour_manual(values=c25)+
geom_vline(xintercept = 0,
linetype = 2,
colour = "lightgray") +
geom_hline(yintercept = 0,
linetype = 2,
colour = "lightgray")+
guides(colour=guide_legend(ncol=2))
p_sed
Save the plot
ggsave(filename = file.path(dataPath,"outputs/NSgnmds_sedclass.png"),
device = "png",
dpi=300 )
gnmds w lanscape
deal with sedclass codes
env_vis<- env_vis %>%
mutate(
landscapeName = case_when(
landscape == "1" ~ "Strandflat",
landscape == "21" ~ "ContSlope",
landscape == "22" ~ "Canyon",
landscape == "31" ~ "Valley",
landscape == "32" ~ "Fjord",
landscape == "41" ~ "DeepPlain",
landscape == "42" ~ "SlopePlain",
landscape == "43" ~ "ShelfPlain",
landscape == "431" ~ "shallowValley"
)
)
p_land <- ggplot(data = env_vis,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
coord_fixed() +
ggtitle("GNMDS coloured by landscape class",
subtitle = "First run") +
geom_point(aes(colour = factor(landscapeName))) +
geom_vline(xintercept = 0,
linetype = 2,
colour = "lightgray") +
geom_hline(yintercept = 0,
linetype = 2,
colour = "lightgray")+
guides(colour=guide_legend(ncol=2))
p_land
Save the plot
ggsave(filename = file.path(dataPath,"outputs/NSgnmds_landscape.png"),
device = "png",
dpi=300 )
Gnmds w gmorph
p_gmo <- ggplot(data = env_vis,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
coord_fixed() +
ggtitle("GNMDS coloured by landscape class",
subtitle = "First run") +
geom_point(aes(colour = factor(gmorph))) +
geom_vline(xintercept = 0,
linetype = 2,
colour = "lightgray") +
geom_hline(yintercept = 0,
linetype = 2,
colour = "lightgray")+
guides(colour=guide_legend(ncol=2))
p_gmo
Save the plot
ggsave(filename = file.path(dataPath,"outputs/NSgnmds_gmorph.png"),
device = "png",
dpi=300 )
cat_var_plots<-p_mld+p_sed+p_land+p_gmo
Save the plot
ggexport(cat_var_plots,
filename = file.path(dataPath,"outputs/NSgnmds_catvar.png"),
width = 1000,
height = 800)
Sample identification in the mdsplot
p_gmo <- ggplot(data = env_vis,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
coord_fixed() +
ggtitle("GNMDS coloured by landscape class",
subtitle = "First run") +
geom_point(aes(colour = factor(SampID))) +
geom_vline(xintercept = 0,
linetype = 2,
colour = "lightgray") +
geom_hline(yintercept = 0,
linetype = 2,
colour = "lightgray")+
guides(colour=FALSE, size=FALSE)
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
ggplotly(p_gmo)
Interactive Dens ordisurf
T.mds<- ggplot(data = env_vis,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
geom_point(aes(colour = swDensRob_avs),
size = 1) +
scale_colour_gradientn(limits = c(1027.5, 1040.7),
colors=c('red','yellow','green'))+
ggtitle("Gnmds coloured by dens (NS)")
ggplotly(T.mds)
Vis proposed Threshold
env_vis$densThresh<-cut(env_sub_meta$swDensRob_avs,
breaks=c(1028,1031.3,1041),
labels=c("LoDens","HiDens"))
Th.mds<- ggplot(data = env_vis,
aes(x = gnmds1,
y = gnmds2)) +
theme_classic() +
geom_point(aes(colour = densThresh),
size = 1) +
# scale_colour_manual(values=cbPalette) +# non-ordered colourblind pallette
scale_colour_brewer(palette = "Set1") + # ordered colourblind pallette
ggtitle("gnmds coloured by categorical dens thresholds")
plot(Th.mds)

Save the plot
ggsave(filename = file.path(dataPath,"outputs/NSgnmds_densThresh1031_3.png"),
device = "png",
dpi=300 )
Saving 7 x 7 in image
Dotplot temperature
dotchart(sort(env_vis$swDensRob_avs), main="Dotchart of dens at Norland Slope")

Dotplot zoomed on 2-4*C
dotchart(sort(env_vis$swDensRob_avs), xlim=c(1031,1032),main="Dotchart of dens between 1031 and 1032 at Norland Slope")

LS0tDQp0aXRsZTogIk1BUkVBTk8gLSBOaU46IE5vcmxhbmQgU2xvcGUgUnVuIg0KYXV0aG9yczogVGhpanMgdmFuIFNvbiwgUnVuZSBIYWx2b3JzZW4sIFJlYmVjY2EgUm9zcywgR2Vub3ZldmEgR29uemFsZXMtTWlyZWxpcywgTWFyZ2FyZXQgRG9sYW4NCmRhdGU6ICJMYXN0IFJlbmRlcmVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDINCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGZpZ193aWR0aDogNw0KICAgIGZpZ19oZWlnaHQ6IDcNCmFsd2F5c19hbGxvd19odG1sOiB0cnVlIA0KLS0tDQoNCiMjIFBhY2thZ2VzDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdnY29ycnBsb3QpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KIyBsaWJyYXJ5KCJoZXJlIikNCiMgbGlicmFyeSgiYm9va2Rvd24iKQ0KIyBsaWJyYXJ5KCJkb3dubG9hZHRoaXMiKQ0KbGlicmFyeSh2ZWdhbikNCmxpYnJhcnkocGx5cikNCmxpYnJhcnkoZTEwNzEpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodmlyaWRpcykNCmxpYnJhcnkoR0dhbGx5KQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeShnZ29yZGlwbG90cykNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkob2NlKQ0KbGlicmFyeShwbG90bHkpDQoNCg0Kc291cmNlKCJnZ19vcmRpc3VyZl92aXJpZGlzLlIiKQ0KYGBgDQoNCg0KIyMgRGF0YQ0KYGBge3J9DQoNCmVudl9zb3J0IDwtIHJlYWQuY3N2KGZpbGUucGF0aChkYXRhUGF0aCwiaW5wdXRzL05TZW52X3NvcnRfMjAyMi0wOS0yMi5jc3YiKSkgJT4lIGFzLmRhdGEuZnJhbWUNCm90dV9zb3J0IDwtIHJlYWQuY3N2KGZpbGUucGF0aChkYXRhUGF0aCwiaW5wdXRzL05Tb3R1X3NvcnRfMjAyMi0wOS0yMi5jc3YiKSkgJT4lIGFzLmRhdGEuZnJhbWUNCg0KdGFibGUoZW52X3NvcnQkU2FtcElEMiA9PSBvdHVfc29ydCRTYW1wSUQpDQoNCiNtdXN0IGJlIHNhbWUgbGVuZ3RoIGFuZCBlcXVhbCB0byB1bmlxdWUgc2FtcGxlIG51bWJlciBsZW5ndGggLSB0aGUgb3JkZXJlZCBsaXN0cyBhcmUgYXNzdW1lZCB0byBiZSBkaXJlY3RseSByZWxhdGFibGUgb24gYSByb3cgYnkgcm93IGJhc2lzDQoNCmRpbShlbnZfc29ydCkNCmRpbShvdHVfc29ydCkNCmBgYA0KDQojIyMjIHJlbW92ZSBhbnkgdmFyaWFibGVzIHdpdGggbm90IGVub3VnaCBjb3ZlcmFnZQ0KYGBge3J9DQoNCmVudl9zb3J0IDwtIGVudl9zb3J0ICU+JSBzZWxlY3QoLWMoIkJPMjJfbGlnaHRib3RtZWFuX2JkbWVhbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJPMjJfbGlnaHRib3RsdG1heF9iZG1lYW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCTzIyX2xpZ2h0Ym90bHRtaW5fYmRtZWFuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQk8yMl9saWdodGJvdHJhbmdlX2JkbWVhbiIpKQ0KYGBgDQoNCg0KIyMjIyBQbG90IG1hcCB0byBjaGVjayBsb2NhdGlvbiBvZiBzYW1wbGVzDQpgYGB7cn0NCmVudl9zb3J0X2xvY2F0aW9uczwtIGdncGxvdChkYXRhID0gZW52X3NvcnQsDQogICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBYLnksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBZKSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBiYXRoeSksDQogICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50Mihsb3cgPSAicmVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSAieWVsbG93IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImdyZWVuIikgKw0KICBnZ3RpdGxlKCJMb2NhdGlvbiBvZiBzYW1wbGVzIGluIHNvcnRlZCBlbnYgZmlsZSIpDQoNCmVudl9zb3J0X2xvY2F0aW9ucw0KYGBgDQoNCg0KIyMjIERhdGEgY2xlYW5pbmcNCmBgYHtyfQ0KIyMgUmVtb3ZpbmcgTkFzDQpvdHVDb21wbCA8LSBvdHVfc29ydFtjb21wbGV0ZS5jYXNlcyhlbnZfc29ydFssIC1jKDE6MjApXSksIF0NCmVudkNvbXBsIDwtIGVudl9zb3J0W2NvbXBsZXRlLmNhc2VzKGVudl9zb3J0WywgLWMoMToyMCldKSwgXQ0KDQojIyBSZW1vdmluZyBvYnNlcnZhdGlvbnMgd2l0aCBsZXNzIHRoYW4gNCBPVFVzDQpzZWwgPC0gcm93U3VtcyhvdHVDb21wbFssIC1jKDE6MildKSA+PSA0DQpvdHVTZWwgPC0gb3R1Q29tcGxbc2VsLCBdDQplbnZTZWwgPC0gZW52Q29tcGxbc2VsLCBdDQoNCg0KIyMgUmVtb3ZpbmcgcGhvc3BoYXRlDQojZW52U2VsIDwtIGVudlNlbCAlPiUgc2VsZWN0KC1waG9zcGhhdGVfbWVhbi50aWYpDQoNCg0KZGltKG90dVNlbCk7IGRpbShlbnZTZWwpDQpgYGANCiMjIyMgU2hvdyB3aGF0IHNhbXBsZXMgYXJlIGxlZnQgYWZ0ZXIgY29tcGxldGUgY2FzZXMgYW5kID40IE9UVXMgZmlsdGVycw0KYGBge3J9DQplbnZfc2VsX2xvY2F0aW9uczwtIGdncGxvdChkYXRhID0gZW52U2VsLA0KICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gWC55LA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gWSkpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gYmF0aHkpLA0KICAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHNjYWxlX2NvbG91cl9ncmFkaWVudDIobG93ID0gInJlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgbWlkID0gInllbGxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJncmVlbiIpICsNCiAgZ2d0aXRsZSgiTG9jYXRpb24gb2Ygc2FtcGxlcyBpbiBzb3J0ZWQgZW52IGZpbGUiKQ0KDQplbnZfc2VsX2xvY2F0aW9ucw0KYGBgDQoNCiMjIyMgU2hvdyB3aGF0IGdvdCByZW1vdmVkIGluIGNvbXBsZXRlIGNhc2VzIGZpbHRlcg0KYGBge3J9DQplbnZDb21wbF9jY3JlbTwtZW52X3NvcnQlPiVmaWx0ZXIoIVNhbXBJRCVpbiVlbnZDb21wbCRTYW1wSUQpDQoNCmVudkNvbXBsX2NjcmVtX2xvY2F0aW9uczwtIGdncGxvdChkYXRhID0gZW52Q29tcGxfY2NyZW0sDQogICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBYLnksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBZKSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBiYXRoeSksDQogICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50Mihsb3cgPSAicmVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSAieWVsbG93IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImdyZWVuIikgKw0KICBnZ3RpdGxlKCJMb2NhdGlvbiBvZiByZW1vdmVkIGNvbXBsZXRlIGNhc2Ugc2FtcGxlcyByZXN1bHRpbmcgaW4gZW52U2VsIGZpbGUiKQ0KDQplbnZDb21wbF9jY3JlbV9sb2NhdGlvbnMNCmBgYA0KIyMjIyBTaG93IHdoYXQgZ290IHJlbW92ZWQgaW4gPDQgT1RVcyBmaWx0ZXINCg0KDQpgYGB7cn0NCmludi5zZWwgPC0gcm93U3VtcyhvdHVDb21wbFssIC1jKDE6MildKSA8IDQNCmVudi5pbnZTZWwgPC0gZW52Q29tcGxbaW52LnNlbCwgXQ0KDQplbnYuaW52U2VsX2xvY2F0aW9uczwtIGdncGxvdChkYXRhID0gZW52LmludlNlbCwNCiAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFgueSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IFkpKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGJhdGh5KSwNCiAgICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV9jb2xvdXJfZ3JhZGllbnQyKGxvdyA9ICJyZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG1pZCA9ICJ5ZWxsb3ciLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAiZ3JlZW4iKSArDQogIGdndGl0bGUoIkxvY2F0aW9uIG9mIHJlbW92ZWQgc2FtcGxlcyB3aXRoIDw0IE9UVXMgcmVzdWx0aW5nIGluIGVudlNlbCBmaWxlIikNCg0KZW52LmludlNlbF9sb2NhdGlvbnMNCg0KYGBgDQoNCiMjIyBbT3B0aW9uYWxdIERhdGEgdGhpbm5pbmcNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBvdHVfcmVkIDwtIG90dTFbMTo1MDAsIF0NCiMgb3R1IDwtIG90dV9yZWQNCiMgDQojIGVudl9yZWQgPC0gZW52WzE6NTAwLCBdDQojIGVudiA8LSBlbnZfcmVkDQpgYGANCg0KIyMjIFdob2xlIGRhdGFzZXQgZm9yIGZpcnN0IHJ1bg0KYGBge3J9DQpvdHU8LW90dVNlbFssLWMoMSldDQplbnY8LWVudlNlbFssIC1jKDEsMzoyMyldDQoNCnRhYmxlKGlzLm5hKG90dSkpDQoNCnRhYmxlKGlzLm5hKGVudikpDQoNCiNzdHIob3R1U2VsKQ0KI3N0cihlbnZTZWwpDQpgYGANCg0KDQojIyMgU3BsaXR0aW5nIGluIHN1YnNldHMNCmBgYHtyfQ0KIyAjIyBDbGFzcyAxDQojIG90dTEgPC0gc3Vic2V0KG90dVNlbCwgZW52U2VsJFNwbGl0UmV2ID09IDEpDQojIGVudjEgPC0gZW52U2VsICU+JSBmaWx0ZXIoU3BsaXRSZXYgPT0gMSkNCiMgDQojICMjIENsYXNzIDINCiMgb3R1MiA8LSBzdWJzZXQob3R1U2VsLCBlbnZTZWwkU3BsaXRSZXYgPT0gMikNCiMgZW52MiA8LSBlbnZTZWwgJT4lIGZpbHRlcihTcGxpdFJldiA9PSAyKQ0KIyANCiMgIyMgQ2xhc3MgNA0KIyBvdHUzIDwtIHN1YnNldChvdHVTZWwsIGVudlNlbCRTcGxpdFJldiA9PSAzKQ0KIyBlbnYzIDwtIGVudlNlbCAlPiUgZmlsdGVyKFNwbGl0UmV2ID09IDMpDQojIA0KIyAjIyBDbGFzcyA0DQojIG90dTQgPC0gc3Vic2V0KG90dVNlbCwgZW52U2VsJFNwbGl0UmV2ID09IDQpDQojIGVudjQgPC0gZW52U2VsICU+JSBmaWx0ZXIoU3BsaXRSZXYgPT0gNCkNCiMgDQojICMjIENsYXNzIDYNCiMgb3R1NiA8LSBzdWJzZXQob3R1U2VsLCBlbnZTZWwkU3BsaXRSZXYgPT0gNikNCiMgZW52NiA8LSBlbnZTZWwgJT4lIGZpbHRlcihTcGxpdFJldiA9PSA2KQ0KIyANCiMgIyMgQ2xhc3MgNw0KIyBvdHU3IDwtIHN1YnNldChvdHVTZWwsIGVudlNlbCRTcGxpdFJldiA9PSA3KQ0KIyBlbnY3IDwtIGVudlNlbCAlPiUgZmlsdGVyKFNwbGl0UmV2ID09IDcpDQojIA0KIyAjIyBDbGFzcyA4DQojIG90dTggPC0gc3Vic2V0KG90dVNlbCwgZW52U2VsJFNwbGl0UmV2ID09IDgpDQojIGVudjggPC0gZW52U2VsICU+JSBmaWx0ZXIoU3BsaXRSZXYgPT0gOCkNCmBgYA0KDQojIyBTZWxlY3Rpbmcgc3Vic2V0DQpgYGB7cn0NCiMgIyMgU2VsZWN0aW5nIA0KIyBvdHUgPC0gb3R1Mg0KIyBlbnYgPC0gZW52Mg0KDQpgYGANCg0KIyMgZm9ybWF0IGRhdGEgY29ycmVjdGx5DQpgYGB7cn0NCiNlbnYkY29vcmRzLngxPC1hcy5udW1lcmljKGVudiRjb29yZHMueDEpDQojZW52JGNvb3Jkcy54MjwtYXMubnVtZXJpYyhlbnYkY29vcmRzLngyKQ0KDQoNCmBgYA0KDQoNCiMjIEFidW5kYW5jZSB3ZWlnaHRpbmcNCk1ha2UgZnVuY3Rpb24NCllvdSBtaWdodCBoYXZlIHRvIGRyb3AgdmFyaWFibGVzIHRoYXQgaGF2ZSBiZWVuIGltcG9ydGVkIGFzIGNoYXJhY3Rlcg0KYGBge3J9DQoNCm90dV9wYSA8LSBkZWNvc3RhbmQoeCA9IG90dVssIC1jKDEpXSwNCiAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gInBhIikNCg0KIyB5ID0gYXhedyAgICAgICAgICMgcG93ZXIgdHJhbnNmb3JtYXRpb24gZm9ybXVsYQ0KZHQgPC0gb3R1WywgLWMoMToyKV0gICAgICAgICAgIyBzcGVjaWVzIGRhdGEgdG8gdHJhbnNmb3JtDQp4X21uIDwtIG1pbihkdFtkdCA+IDBdKQ0KeF9teCA8LSBtYXgoZHQpDQpybmcgPC0gNiAgICAgICAgICAgIyBhYnVuZGFuY2UgcmFuZ2UNCncgPC0gbG9nKHJuZykgLyAobG9nKHhfbXgpIC0gbG9nKHhfbW4pKQ0KYSA8LSB4X21uXigtdykNCiMgb3R1XzYgPC0gYSAqIGR0WywgLWMoMTozKV1edw0Kb3R1XzYgPC0gYSAqIGR0XncNCnJhbmdlKG90dV82KQ0KYGBgDQoNCiMjIE9yZGluYXRpb24gbWV0aG9kcw0KIyMjIERDQSBQQQ0KYGBge3J9DQpkY2FfcGEgPC0gZGVjb3JhbmEodmVnID0gb3R1X3BhKQ0KDQpwcmludChkY2FfcGEsIGhlYWQ9VCkNCmBgYA0KDQoNCiMjIyBHTk1EUyBQQQ0KDQojIyMjIERpc3RhbmNlcyAtIGRvbid0IHJ1biBpZiBsb2FkaW5nIHNhdmVkIG9iamVjdA0KDQpgYGB7cn0NCiMjIEJyYXktQ3VydGlzDQpkaXN0X3BhIDwtIHZlZ2Rpc3QoeCA9IG90dV9wYSwgbWV0aG9kID0gImJyYXkiKQ0KDQojIyBHZW9kaXN0DQplcCA8LSAwLjggICAgICMgZXBzaWxvbg0KZ2VvZGlzdF9wYSA8LSBpc29tYXBkaXN0KGRpc3QgPSBkaXN0X3BhLCBlcHNpbG9uID0gZXApDQpgYGANCg0KDQojIyMjIyBTYXZlIHRoZSByZXN1bHQgLSBkb24ndCBydW4gaWYgbG9hZGluZyBzYXZlZCBvYmplY3QNCmBgYHtyfQ0Kc2F2ZVJEUyhnZW9kaXN0X3BhLA0KICAgICAgICBmaWxlID0gKGZpbGUucGF0aChkYXRhUGF0aCwiaW5wdXRzL05TZ2VvZGlzdF9wYS5yZHMiKSkpDQpgYGANCg0KIyMjIyBPcmRpbmF0aW9uDQoNCiMjIyMgbW9ub01EUyAtIGRvbid0IHJ1biBpZiBsb2FkaW5nIHNhdmVkIG9iamVjdA0KdGFrZXMgMTAgc2Vjcw0KYGBge3J9DQoNClN5cy50aW1lKCkNCmQgPC0gMg0KbWRzX3BhIDwtIGxpc3QoKQ0KDQpmb3IgKGkgaW4gMToxMDApIHsNCiAgbWRzX3BhW1tpXV08LW1vbm9NRFMoZ2VvZGlzdF9wYSwNCiAgICAgICAgICAgICAgICAgICAgbWF0cml4KGMocnVuaWYoZGltKG90dV9wYSlbMV0qZCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IGRpbShvdHVfcGEpWzFdKSwNCiAgICAgICAgICAgICAgICAgICAgayA9IGQsDQogICAgICAgICAgICAgICAgICAgIG1vZGVsID0gImdsb2JhbCIsDQogICAgICAgICAgICAgICAgICAgIG1heGl0ID0gMjAwMCwNCiAgICAgICAgICAgICAgICAgICAgc21pbiA9IDFlLTcsDQogICAgICAgICAgICAgICAgICAgIHNmZ3JtaW4gPSAxZS03KQ0KfQ0KDQpgYGANCg0KIyMjIyMgU2F2ZSB0aGUgcmVzdWx0IC0gZG9uJ3QgcnVuIGlmIGxvYWRpbmcgc2F2ZWQgb2JqZWN0DQpgYGB7cn0NCnNhdmVSRFMobWRzX3BhLA0KICAgICAgICBmaWxlID0gZmlsZS5wYXRoKGRhdGFQYXRoLCJpbnB1dHMvTlNtZHNfcGEucmRzIikpDQpgYGANCg0KDQojIyMjIyBCZXN0IG5tZHMgc29sdXRpb24gLSBQQQ0KTWFrZSBmdW5jdGlvbj8NCmBgYHtyLCBldmFsPVRSVUV9DQojIExvYWRpbmcgZ2VvZGlzdCBvYmplY3QNCiMgZ2VvZGlzdF9uZmkgPC0gcmVhZFJEUyhmaWxlID0gIi4uL1NwbGl0UmV2Ml9nZW9kaXN0X3BhX2Z1bGwucmRzIikNCmBgYA0KDQoNCmBgYHtyfQ0KIyBMb2FkaW5nIG1kcyByZXN1bHRzDQojIG1kcyA8LSByZWFkUkRTKGZpbGUgPSAiLi4vU3BsaXRSZXYyX21kc19wYV9mdWxsLnJkcyIpDQoNCiMjIEV4dHJhY3RpbmcgdGhlIHN0cmVzcyBvZiBlYWNoIG5tZHMgaXRlcmF0aW9uDQptZHNfc3RyZXNzX3BhPC11bmxpc3QobGFwcGx5KG1kc19wYSwgZnVuY3Rpb24odil7dltbMjJdXX0pKSANCg0Kb3JkZXJlZF9wYSA8LW9yZGVyKG1kc19zdHJlc3NfcGEpDQoNCiMjIEJlc3QsIHNlY29uZCBiZXN0LCBhbmQgd29yc3Qgc29sdXRpb24NCm1kc19zdHJlc3NfcGFbb3JkZXJlZF9wYVsxXV0NCm1kc19zdHJlc3NfcGFbb3JkZXJlZF9wYVsyXV0NCm1kc19zdHJlc3NfcGFbb3JkZXJlZF9wYVsxMF1dDQoNCiMjIFNjYWxpbmcgb2YgYXhlcyB0byBoYWxmIGNoYW5nZSB1bml0cyBhbmQgdmFyaW1heCByb3RhdGlvbiBieSBwb3N0TURTDQptZHNfYmVzdF9wYTwtcG9zdE1EUyhtZHNfcGFbW29yZGVyZWRfcGFbMV1dXSwNCiAgICAgICAgICAgICAgICAgIGdlb2Rpc3RfcGEsIA0KICAgICAgICAgICAgICAgICAgcGMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgIGhhbGZjaGFuZ2UgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IGVwKSAgICAgIyBJcyB0aGlzIHRocmVzaG9sZCByZWxhdGVkIHRvIHRoZSBlcHNpbG9uIGFib3ZlPw0KbWRzX2Jlc3RfcGENCg0KbWRzX3NlY2Jlc3RfcGEgPC0gcG9zdE1EUyhtZHNfcGFbW29yZGVyZWRfcGFbMl1dXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvZGlzdF9wYSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHBjID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGhhbGZjaGFuZ2UgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZXNob2xkID0gZXApDQptZHNfc2VjYmVzdF9wYQ0KDQojIyBQcm9jcnVzdGVzIGNvbXBhcmlzb25zDQpwcm9jcl9wYSA8LSBwcm9jcnVzdGVzKG1kc19iZXN0X3BhLA0KICAgICAgICAgICAgICAgICAgICBtZHNfc2VjYmVzdF9wYSwNCiAgICAgICAgICAgICAgICAgICAgcGVybXV0YXRpb25zPTk5OSkNCnByb3Rlc3QobWRzX2Jlc3RfcGEsDQogICAgICAgIG1kc19zZWNiZXN0X3BhLA0KICAgICAgICBwZXJtdXRhdGlvbnM9OTk5KQ0KDQpwbG90KHByb2NyX3BhKQ0KDQpwbmcoZmlsZT1maWxlLnBhdGgoZGF0YVBhdGgsIm91dHB1dHMvTlNwcm9jcnVzdGVzX3BhLnBuZyIpLCB3aWR0aD0xMDAwLCBoZWlnaHQ9NzAwKQ0KcGxvdChwcm9jcl9wYSkNCmRldi5vZmYoKQ0KYGBgDQoNCiMjIyMjIENvcnJlbGF0aW9uIG9mIGF4aXM6IERDQSB2cyBOTURTIC0gUEENCmBgYHtyfQ0KIyBFeHRyYWN0aW5nIG9yZGluYXRpb24gYXhpcw0KYXggPC0gMg0KYXhpc19wYSA8LSBjYmluZChtZHNfYmVzdF9wYSRwb2ludHMsDQogICAgICAgICAgICAgICAgIHNjb3JlcyhkY2FfcGEsDQogICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5ID0gInNpdGVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpbiA9IFRSVUUpWywgMTpheF0pDQoNCmdnY29ycihheGlzX3BhLCANCiAgICAgICBtZXRob2Q9YygiZXZlcnl0aGluZyIsImtlbmRhbGwiKSwgDQogICAgICAgbGFiZWwgPSBUUlVFLA0KICAgICAgIGxhYmVsX3NpemUgPSAzLCANCiAgICAgICBsYWJlbF9jb2xvciA9ICJibGFjayIsICANCiAgICAgICBuYnJlYWtzID0gOCwNCiAgICAgICBsYWJlbF9yb3VuZCA9IDMsDQogICAgICAgbG93ID0gInJlZCIsDQogICAgICAgbWlkID0gIndoaXRlIiwNCiAgICAgICBoaWdoID0gImdyZWVuIikNCg0KDQpgYGANCg0KIyMjIyMgU2F2ZSB0aGUgZmlndXJlDQpgYGB7cn0NCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGUucGF0aChkYXRhUGF0aCwib3V0cHV0cy9OU2NvcnJlbGF0aW9uUENBdnNOTURTX1BBLnBuZyIpLA0KICAgICAgIGRldmljZSA9ICJwbmciLA0KICAgICAgIGRwaT0zMDAgKQ0KDQojIFN3aXRjaGluZyBkaXJlY3Rpb24gb2YgTk1EUzENCiMgbWRzX2Jlc3QkcG9pbnRzWywgMV0gPC0gLW1kc19iZXN0JHBvaW50c1ssIDFdDQpgYGANCg0KIyMjIERDQSBSNg0KYGBge3J9DQpkY2FfcjYgPC0gZGVjb3JhbmEodmVnID0gb3R1XzYpDQoNCnByaW50KGRjYV9yNiwgaGVhZD1UKQ0KYGBgDQoNCg0KIyMjIEdOTURTIFI2DQojIyMjIERpc3RhbmNlcyAtIGRvbid0IHJ1biBpZiBsb2FkaW5nIHNhdmVkIG9iamVjdA0KYGBge3J9DQojIyBCcmF5LUN1cnRpcw0KZGlzdF9yNiA8LSB2ZWdkaXN0KHggPSBvdHVfNiwgbWV0aG9kID0gImJyYXkiKQ0KDQojIyBHZW9kaXN0DQplcCA8LSAwLjgwICAgICAjIGVwc2lsb24NCmdlb2Rpc3RfcjYgPC0gaXNvbWFwZGlzdChkaXN0ID0gZGlzdF9yNiwgZXBzaWxvbiA9IGVwKQ0KYGBgDQoNCiMjIyMjIFNhdmUgdGhlIHJlc3VsdCAtIGRvbid0IHJ1biBpZiBsb2FkaW5nIHNhdmVkIG9iamVjdA0KYGBge3J9DQpzYXZlUkRTKGdlb2Rpc3RfcjYsDQogICAgICAgIGZpbGUgPSAoZmlsZS5wYXRoKGRhdGFQYXRoLCJpbnB1dHMvTlNnZW9kaXN0X3I2LnJkcyIpKSkNCmBgYA0KDQoNCiMjIyMgT3JkaW5hdGlvbiANCg0KIyMjIyMgMjAwIHJlcHMgLSBkb24ndCBydW4gaWYgbG9hZGluZyBzYXZlZCBvYmplY3QNCnRvb2sgMjAgc2Vjcw0KYGBge3J9DQojIG1vbm9NRFMNCmQgPC0gMg0KbWRzX3I2IDwtIGxpc3QoKQ0KDQpTeXMudGltZSgpDQpmb3IgKGkgaW4gMToyMDApIHsNCiAgbWRzX3I2W1tpXV08LW1vbm9NRFMoZ2VvZGlzdF9yNiwNCiAgICAgICAgICAgICAgICAgICAgbWF0cml4KGMocnVuaWYoZGltKG90dV82KVsxXSpkKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gZGltKG90dV82KVsxXSksDQogICAgICAgICAgICAgICAgICAgIGsgPSBkLA0KICAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJnbG9iYWwiLA0KICAgICAgICAgICAgICAgICAgICBtYXhpdCA9IDIwMDAsDQogICAgICAgICAgICAgICAgICAgIHNtaW4gPSAxZS03LA0KICAgICAgICAgICAgICAgICAgICBzZmdybWluID0gMWUtNykNCn0NClN5cy50aW1lKCkNCmBgYA0KDQojIyMjIyBTYXZlIHRoZSByZXN1bHQgLSBkb24ndCBydW4gaWYgbG9hZGluZyBzYXZlZCBvYmplY3QNCmBgYHtyfQ0Kc2F2ZVJEUyhtZHNfcjYsDQogICAgICAgIGZpbGUgPSBmaWxlLnBhdGgoZGF0YVBhdGgsImlucHV0cy9OU21kc19yNi5yZHMiKSkgDQpgYGANCg0KIyMjIyMgQmVzdCBubWRzIHNvbHV0aW9uIHI2IDIwMCByZXAgDQpgYGB7ciwgZXZhbD1UUlVFfQ0KIyBMb2FkaW5nIGdlb2Rpc3Qgb2JqZWN0DQojIGdlb2Rpc3RfbmZpIDwtIHJlYWRSRFMoZmlsZSA9ICIuLi9TcGxpdFJldjJfZ2VvZGlzdF9uZmkucmRzIikNCg0KIyBMb2FkaW5nIG1kcyByZXN1bHRzDQojIG1kcyA8LSByZWFkUkRTKGZpbGUgPSAiLi4vU3BsaXRSZXYyX21kcy5yZHMiKQ0KDQojIyBFeHRyYWN0aW5nIHRoZSBzdHJlc3Mgb2YgZWFjaCBubWRzIGl0ZXJhdGlvbg0KbWRzX3N0cmVzc19yNjwtdW5saXN0KGxhcHBseShtZHNfcjYsIGZ1bmN0aW9uKHYpe3ZbWzIyXV19KSkgDQoNCm9yZGVyZWRfcjYgPC1vcmRlcihtZHNfc3RyZXNzX3I2KQ0KDQojIyBCZXN0LCBzZWNvbmQgYmVzdCwgYW5kIHdvcnN0IHNvbHV0aW9uDQptZHNfc3RyZXNzX3I2W29yZGVyZWRfcjZbMV1dDQptZHNfc3RyZXNzX3I2W29yZGVyZWRfcjZbMl1dDQptZHNfc3RyZXNzX3I2W29yZGVyZWRfcjZbMTAwXV0NCg0KIyMgU2NhbGluZyBvZiBheGVzIHRvIGhhbGYgY2hhbmdlIHVuaXRzIGFuZCB2YXJpbWF4IHJvdGF0aW9uIGJ5IHBvc3RNRFMNCm1kc19iZXN0X3I2PC1wb3N0TURTKG1kc19yNltbb3JkZXJlZF9yNlsxXV1dLA0KICAgICAgICAgICAgICAgICAgICAgZ2VvZGlzdF9yNiwgDQogICAgICAgICAgICAgICAgICAgICBwYyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgaGFsZmNoYW5nZSA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgdGhyZXNob2xkID0gZXApICAgICAjIElzIHRoaXMgdGhyZXNob2xkIHJlbGF0ZWQgdG8gdGhlIGVwc2lsb24gYWJvdmU/DQptZHNfYmVzdF9yNg0KDQptZHNfc2VjYmVzdF9yNjwtcG9zdE1EUyhtZHNfcjZbW29yZGVyZWRfcjZbMl1dXSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb2Rpc3RfcjYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgcGMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGhhbGZjaGFuZ2UgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHRocmVzaG9sZCA9IGVwKQ0KbWRzX3NlY2Jlc3RfcjYNCg0KIyMgUHJvY3J1c3RlcyBjb21wYXJpc29ucw0KcHJvY3JfcjYgPC0gcHJvY3J1c3RlcyhtZHNfYmVzdF9yNiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWRzX3NlY2Jlc3RfcjYsDQogICAgICAgICAgICAgICAgICAgICAgIHBlcm11dGF0aW9ucz05OTkpDQpwcm90ZXN0KG1kc19iZXN0X3I2LA0KICAgICAgICBtZHNfc2VjYmVzdF9yNiwNCiAgICAgICAgcGVybXV0YXRpb25zPTk5OSkNCg0KcGxvdChwcm9jcl9yNikNCg0KcG5nKGZpbGUucGF0aChkYXRhUGF0aCwib3V0cHV0cy9OU3Byb2NydXN0ZXNfcjYucG5nIiksIHdpZHRoPTEwMDAsIGhlaWdodD03MDAsKSAjYWRkZWQgMTAwMA0KcGxvdChwcm9jcl9yNikNCmRldi5vZmYoKQ0KYGBgDQoNCiAjIyMjIDEwMDAgcmVwcyAtIGRvbid0IHJ1biBpZiBsb2FkaW5nIHNhdmVkIG9iamVjdCANCiBDdXJyZW50bHkgY29tbWVudGVkIG91dCBhcyBpdCBnYWluZWQgbm90aGluZyBidXQgdG9vayBleHRyYSB0aW1lLiBDYW4gYmUgcmVtb3ZlZCBpbiBkdWUgY291cnNlLg0KPCEtLSB0b29rIDFociAtLT4NCjwhLS0gYGBge3J9IC0tPg0KPCEtLSAjIG1vbm9NRFMgLS0+DQo8IS0tIGQgPC0gMiAtLT4NCjwhLS0gbWRzX3I2XzEwMDAgPC0gbGlzdCgpI29iaiBhZGRlZF8xMDAwIC0tPg0KDQo8IS0tIFN5cy50aW1lKCkgLS0+DQo8IS0tIGZvciAoaSBpbiAxOjEwMDApIHsjY2hhbmdlIGZyb20gMjAwICgyMDAgcmEgaW4gMjBtaW4sIDEwMDAgcmFuIGluIDFocikgLS0+DQo8IS0tICAgbWRzX3I2XzEwMDBbW2ldXTwtbW9ub01EUyhnZW9kaXN0X3I2LCNvYmogYWRkZWQgXzEwMDAgLS0+DQo8IS0tICAgICAgICAgICAgICAgICAgICAgbWF0cml4KGMocnVuaWYoZGltKG90dV82KVsxXSpkKSksIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gZGltKG90dV82KVsxXSksIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgIGsgPSBkLCAtLT4NCjwhLS0gICAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJnbG9iYWwiLCAtLT4NCjwhLS0gICAgICAgICAgICAgICAgICAgICBtYXhpdCA9IDIwMDAsIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgIHNtaW4gPSAxZS03LCAtLT4NCjwhLS0gICAgICAgICAgICAgICAgICAgICBzZmdybWluID0gMWUtNykgLS0+DQo8IS0tIH0gLS0+DQo8IS0tIFN5cy50aW1lKCkgLS0+DQo8IS0tIGBgYCAtLT4NCg0KPCEtLSAjIyMjIyBTYXZlIHRoZSByZXN1bHQgLSBkb24ndCBydW4gaWYgbG9hZGluZyBzYXZlZCBvYmplY3QgLS0+DQo8IS0tIGBgYHtyfSAtLT4NCjwhLS0gc2F2ZVJEUyhtZHNfcjZfMTAwMCwgI29iaiBhZGRlZF8xMDAwIC0tPg0KPCEtLSAgICAgICAgIGZpbGUgPSBmaWxlLnBhdGgoZGF0YVBhdGgsImlucHV0cy9tZHNfcjZfMTAwMHJlcC5yZHMiKSkgI2NoYW5nZSBmcm9tIDIwMCAtLT4NCjwhLS0gYGBgIC0tPg0KDQo8IS0tICMjIyMjIEJlc3Qgbm1kcyBzb2x1dGlvbiByNiAxMDAwIHJlcCAtLT4NCjwhLS0gYGBge3IsIGV2YWw9VFJVRX0gLS0+DQo8IS0tICMgTG9hZGluZyBnZW9kaXN0IG9iamVjdCAtLT4NCjwhLS0gIyBnZW9kaXN0X25maSA8LSByZWFkUkRTKGZpbGUgPSAiLi4vU3BsaXRSZXYyX2dlb2Rpc3RfbmZpLnJkcyIpIC0tPg0KDQo8IS0tICMgTG9hZGluZyBtZHMgcmVzdWx0cyAtLT4NCjwhLS0gIyBtZHMgPC0gcmVhZFJEUyhmaWxlID0gIi4uL1NwbGl0UmV2Ml9tZHMucmRzIikgLS0+DQoNCjwhLS0gIyMgRXh0cmFjdGluZyB0aGUgc3RyZXNzIG9mIGVhY2ggbm1kcyBpdGVyYXRpb24gLS0+DQo8IS0tIG1kc19zdHJlc3NfcjZfMTAwMDwtdW5saXN0KGxhcHBseShtZHNfcjZfMTAwMCwgZnVuY3Rpb24odil7dltbMjJdXX0pKSAjYWRlZWQgMTAwMCAtLT4NCg0KPCEtLSBvcmRlcmVkX3I2XzEwMDAgPC1vcmRlcihtZHNfc3RyZXNzX3I2XzEwMDApIC0tPg0KDQo8IS0tICMjIEJlc3QsIHNlY29uZCBiZXN0LCBhbmQgd29yc3Qgc29sdXRpb24gLS0+DQo8IS0tIG1kc19zdHJlc3NfcjZfMTAwMFtvcmRlcmVkX3I2XzEwMDBbMV1dIC0tPg0KPCEtLSBtZHNfc3RyZXNzX3I2XzEwMDBbb3JkZXJlZF9yNl8xMDAwWzJdXSAtLT4NCjwhLS0gbWRzX3N0cmVzc19yNl8xMDAwW29yZGVyZWRfcjZfMTAwMFsxMDBdXSAtLT4NCg0KPCEtLSAjIyBTY2FsaW5nIG9mIGF4ZXMgdG8gaGFsZiBjaGFuZ2UgdW5pdHMgYW5kIHZhcmltYXggcm90YXRpb24gYnkgcG9zdE1EUyAtLT4NCjwhLS0gbWRzX2Jlc3RfcjZfMTAwMDwtcG9zdE1EUyhtZHNfcjZfMTAwMFtbb3JkZXJlZF9yNl8xMDAwWzFdXV0sIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICBnZW9kaXN0X3I2LCAgLS0+DQo8IS0tICAgICAgICAgICAgICAgICAgICAgIHBjID0gVFJVRSwgIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICBoYWxmY2hhbmdlID0gVFJVRSwgIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSBlcCkgICAgICMgSXMgdGhpcyB0aHJlc2hvbGQgcmVsYXRlZCB0byB0aGUgZXBzaWxvbiBhYm92ZT8gLS0+DQo8IS0tIG1kc19iZXN0X3I2XzEwMDAgLS0+DQoNCjwhLS0gbWRzX3NlY2Jlc3RfcjZfMTAwMDwtcG9zdE1EUyhtZHNfcjZfMTAwMFtbb3JkZXJlZF9yNl8xMDAwWzJdXV0sIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICBnZW9kaXN0X3I2LCAgLS0+DQo8IS0tICAgICAgICAgICAgICAgICAgICAgICAgIHBjID0gVFJVRSwgIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICBoYWxmY2hhbmdlID0gVFJVRSwgIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSBlcCkgLS0+DQo8IS0tIG1kc19zZWNiZXN0X3I2XzEwMDAgLS0+DQoNCjwhLS0gIyMgUHJvY3J1c3RlcyBjb21wYXJpc29ucyAtLT4NCjwhLS0gcHJvY3JfcjZfMTAwMCA8LSBwcm9jcnVzdGVzKG1kc19iZXN0X3I2XzEwMDAsIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgIG1kc19zZWNiZXN0X3I2XzEwMDAsIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgIHBlcm11dGF0aW9ucz05OTkpIC0tPg0KPCEtLSBwcm90ZXN0KG1kc19iZXN0X3I2XzEwMDAsIC0tPg0KPCEtLSAgICAgICAgIG1kc19zZWNiZXN0X3I2XzEwMDAsIC0tPg0KPCEtLSAgICAgICAgIHBlcm11dGF0aW9ucz05OTkpIC0tPg0KDQo8IS0tIHBsb3QocHJvY3JfcjZfMTAwMCkgLS0+DQoNCjwhLS0gcG5nKGZpbGUucGF0aChkYXRhUGF0aCwib3V0cHV0cy9wcm9jcnVzdGVzX3I2XzEwMDAucG5nIiksIHdpZHRoPTEwMDAsIGhlaWdodD03MDAsKSAjYWRkZWQgMTAwMCAtLT4NCjwhLS0gcGxvdChwcm9jcl9yNl8xMDAwKSAtLT4NCjwhLS0gZGV2Lm9mZigpIC0tPg0KPCEtLSBgYGAgLS0+DQoNCg0KDQojIyMjIyBDb3JyZWxhdGlvbiBvZiBheGlzOiBEQ0EgdnMgTk1EUyANCnJldGFpbiB0aGUgMjAwIHJlcCB2ZXJzaW9uDQpgYGB7cn0NCiMgRXh0cmFjdGluZyBvcmRpbmF0aW9uIGF4aXMNCmF4IDwtIDINCmF4aXNfcjYgPC0gY2JpbmQobWRzX2Jlc3RfcjYkcG9pbnRzLA0KICAgICAgICAgICAgICAgICBzY29yZXMoZGNhX3I2LA0KICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheSA9ICJzaXRlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW4gPSBUUlVFKVssIDE6YXhdKQ0KDQpnZ2NvcnIoYXhpc19yNiwgDQogICAgICAgbWV0aG9kPWMoImV2ZXJ5dGhpbmciLCJrZW5kYWxsIiksIA0KICAgICAgIGxhYmVsID0gVFJVRSwNCiAgICAgICBsYWJlbF9zaXplID0gMywgDQogICAgICAgbGFiZWxfY29sb3IgPSAiYmxhY2siLCAgDQogICAgICAgbmJyZWFrcyA9IDgsDQogICAgICAgbGFiZWxfcm91bmQgPSAzLA0KICAgICAgIGxvdyA9ICJyZWQiLA0KICAgICAgIG1pZCA9ICJ3aGl0ZSIsDQogICAgICAgaGlnaCA9ICJncmVlbiIpDQoNCmBgYA0KDQojIyMjIyBTYXZlIHRoZSBmaWd1cmUNCmBgYHtyfQ0KZ2dzYXZlKGZpbGVuYW1lID0gZmlsZS5wYXRoKGRhdGFQYXRoLCJvdXRwdXRzL05TY29ycmVsYXRpb25QQ0F2c05NRFNfcjYucG5nIiksDQogICAgICAgZGV2aWNlID0gInBuZyIsDQogICAgICAgZHBpPTMwMCApDQoNCiMgU3dpdGNoaW5nIGRpcmVjdGlvbiBvZiBOTURTMQ0KIyBtZHNfYmVzdCRwb2ludHNbLCAxXSA8LSAtbWRzX2Jlc3QkcG9pbnRzWywgMV0NCmBgYA0KDQojIyMgUGxvdHRpbmcgRENBICYgR05NRFMNCmBgYHtyfQ0KIyMgQWRkaW5nIHNjb3JlcyB0byBkYXRhIGZyYW1lDQpvdHVfNiRnbm1kczEgPC0gbWRzX2Jlc3RfcjYkcG9pbnRzWywgMV0NCm90dV82JGdubWRzMiA8LSBtZHNfYmVzdF9yNiRwb2ludHNbLCAyXQ0Kb3R1XzYkZGNhMSA8LSBzY29yZXMoZGNhX3I2LCBkaXNwbGF5ID0gInNpdGVzIiwgb3JpZ2luID0gVFJVRSlbLCAxXQ0Kb3R1XzYkZGNhMiA8LSBzY29yZXMoZGNhX3I2LCBkaXNwbGF5ID0gInNpdGVzIiwgb3JpZ2luID0gVFJVRSlbLCAyXQ0KDQpwX2dubWRzX3I2IDwtIGdncGxvdChkYXRhID0gb3R1XzYsDQogICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGdubWRzMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZ25tZHMyKSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9maXhlZCgpICsNCiAgZ2d0aXRsZSgiR05NRFMiLA0KICAgICAgICAgIHN1YnRpdGxlID0gIkZpcnN0IHJ1biIpICsNCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAicmVkIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAibGlnaHRncmF5IikgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAibGlnaHRncmF5IikNCg0KcF9kY2FfcjYgPC0gZ2dwbG90KGRhdGEgPSBvdHVfNiwNCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGRjYTEsDQogICAgICAgICAgICAgICAgICAgICAgIHkgPSAtZGNhMikpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZml4ZWQoKSArDQogIGdndGl0bGUoIkRDQSIsDQogICAgICAgICAgc3VidGl0bGUgPSAiRmlyc3QgcnVuIikgKw0KICBnZW9tX3BvaW50KGNvbG91ciA9ICJyZWQiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsDQogICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgIGNvbG91ciA9ICJsaWdodGdyYXkiKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsDQogICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgIGNvbG91ciA9ICJsaWdodGdyYXkiKQ0KDQpwX2dubWRzX3I2ICsgcF9kY2FfcjYNCg0KDQpgYGANCg0KIyMjIyMgU2F2ZSB0aGUgZmlndXJlDQpgYGB7cn0NCmdnc2F2ZShmaWxlLnBhdGgoZGF0YVBhdGgsIm91dHB1dHMvTlNnbm1kc19kY2FfcjYucG5nIiksDQogICAgICAgZGV2aWNlID0gInBuZyIsIA0KICAgICAgIGRwaT0zMDApDQpgYGANCg0KIyMgU3BlY2llcy1lbnZpcm9ubWVudCByZWxhdGlvbnNoaXBzDQojIyMgU2VsZWN0aW5nIG9yZGluYXRpb24NCmBgYHtyfQ0Kb3JkIDwtIG1kc19iZXN0X3I2DQoNCiMjIEF4aXMgc2NvcmVzIGlmIHNlbGVjdGVkIG9yZCBpcyBHTk1EUw0KYXhpcyA8LSBvcmQkcG9pbnRzICU+JSBhcy5kYXRhLmZyYW1lDQoNCiMjIEF4aXMgc2NvcmVzIGlmIHNlbGVjdGVkIG9yZCBpcyBEQ0ENCiMgYXhpcyA8LSBzY29yZXMob3JkLA0KIyAgICAgICAgICAgICAgICBkaXNwbGF5ID0gInNpdGVzIiwNCiMgICAgICAgICAgICAgICAgb3JpZ2luID0gVFJVRSlbLCAxOmF4XSkNCg0KYGBgDQoNCiMjIyBDcmVhdGUgYWRkaXRpb25hbCB2YXJpYWJsZXMNCmRlY2lkZWQgdG8gbWFrZSBNTEQtYmF0aHkgdmFycw0KYGBge3J9DQplbnY8LWVudiAlPiUgDQogIG11dGF0ZSAoIk1MRG1lYW5fYmF0aHkiPU1MRG1lYW5fUm9iaW5zb24tKGJhdGh5Ki0xKSwNCiAgICAgICAgICAiTUxEbWluX2JhdGh5Ij1NTERtaW5fUm9iaW5zb24tKGJhdGh5Ki0xKSwNCiAgICAgICAgICAiTUxEbWF4X2JhdGh5Ij1NTERtYXhfUm9iaW5zb24tKGJhdGh5Ki0xKSkNCg0KZW52JE1MRG1lYW5fYmF0aHk8LWN1dChlbnYkTUxEbWVhbl9iYXRoeSwgDQogICAgICBicmVha3M9YygtMjU2MCwgLTIwLDIwLDEzMCksI2NoZWNrZWQgcmFuZ2Ugb2YgdmFsdWVzIGZpcnN0IChtaW4gLTI1NTQsIG1heCAxMjMpDQogICAgICBsYWJlbHM9YygnYmVsb3dNTEQnLCdvblB5Y25vJywnaW5NaXhMYXllcicpKQ0KZW52JE1MRG1pbl9iYXRoeTwtY3V0KGVudiRNTERtaW5fYmF0aHksIA0KICAgICAgYnJlYWtzPWMoLTI1NjAsIC0yMCwyMCwxMzApLCNjaGVja2VkIHJhbmdlIG9mIHZhbHVlcyBmaXJzdCAobWluIC0yNTU0LCBtYXggMTIzKQ0KICAgICAgbGFiZWxzPWMoJ2JlbG93TUxEJywnb25QeWNubycsJ2luTWl4TGF5ZXInKSkNCmVudiRNTERtYXhfYmF0aHk8LWN1dChlbnYkTUxEbWF4X2JhdGh5LCANCiAgICAgIGJyZWFrcz1jKC0yNTYwLCAtMjAsMjAsMTMwKSwjY2hlY2tlZCByYW5nZSBvZiB2YWx1ZXMgZmlyc3QgKG1pbiAtMjU1NCwgbWF4IDEyMykNCiAgICAgIGxhYmVscz1jKCdiZWxvd01MRCcsJ29uUHljbm8nLCdpbk1peExheWVyJykpDQoNCmVudiRzd0RlbnNSb2JfYXZzPC1zd1JobyhzYWxpbml0eT1lbnYkU21lYW5fUm9iaW5zb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgdGVtcGVyYXR1cmU9ZW52JFRtZWFuX1JvYmluc29uLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHByZXNzdXJlPShlbnYkYmF0aHkqLTEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGVvcz0idW5lc2NvIikNCg0KYGBgDQoNCg0KDQojIyMgQ29ycmVsYXRpb24gb3JkaW5hdGlvbiBheGVzIGFuZCBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcw0KIyMjIyBSZW1vdmluZyBub24tZW52IHZhcnMNCmBgYHtyfQ0KZW52X2NvbnQ8LWVudiU+JSBzZWxlY3QoLWMobGFuZHNjYXBlLHNlZGNsYXNzLGdtb3JwaCwgTUxEbWVhbl9iYXRoeSwgTUxEbWF4X2JhdGh5LCBNTERtaW5fYmF0aHksICNjYXRlZ29yaWNhbA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWwsICNub3QgYSB2YXINCiAgICAgICAgICAgICAgICAgICAgICAgICAgIE1MRG1heF9Sb2JpbnNvbiwgTUxEbWVhbl9Sb2JpbnNvbiwgTUxEbWluX1JvYmluc29uLCAgI3JlcGxhY2VkIGJ5IG5ldyB2YXJzDQogICAgICAgICAgICAgICAgICAgICAgICAgICBNTERzZF9Sb2JpbnNvbiAjbm90IG1lYW5pbmdmdWwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICkpDQplbnZfY29udDwtZW52X2NvbnQlPiUgbXV0YXRlX2lmKGlzLmludGVnZXIsYXMubnVtZXJpYykNCmVudl9jb3JyIDwtIGVudl9jb250ICU+JSBzZWxlY3QoLWMoU2FtcElEKSkNCg0KIyBlbnZfY29yciRjb29yZHMueDE8LWFzLm51bWVyaWMoZW52X2NvcnIkY29vcmRzLngxKQ0KIyBlbnZfY29yciRjb29yZHMueDI8LWFzLm51bWVyaWMoZW52X2NvcnIkY29vcmRzLngyKQ0KDQplbnZfY29yclsoIWlzLm51bWVyaWMoZW52X2NvcnIpKSxdDQpgYGANCg0KIyMjIyBDb3JyZWxhdGlvbnMNCmBgYHtyfQ0KIyBWZWN0b3IgdG8gaG9sZCBjb3JyZWxhdGlvbnMNCmNvcl9heDEgPC0gTlVMTA0KY29yX2F4MiA8LSBOVUxMDQpwdl9heDEgPC0gTlVMTA0KcHZfYXgyIDwtIE5VTEwNCg0KIyBOTURTMQ0KZm9yKCBpIGluIHNlcShsZW5ndGgoZW52X2NvcnIpKSkgew0KICBjdC5pIDwtIGNvci50ZXN0KGF4aXMkTURTMSwNCiAgICAgICAgICAgICAgICAgICBlbnZfY29yclssIGldLA0KICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJrZW5kYWxsIikNCiAgY29yX2F4MVtpXSA8LSBjdC5pJGVzdGltYXRlDQogIHB2X2F4MVtpXSA8LSBjdC5pJHAudmFsdWUNCn0NCg0KIyBOTURTMg0KZm9yKCBpIGluIHNlcShsZW5ndGgoZW52X2NvcnIpKSkgew0KICBjdC5pIDwtIGNvci50ZXN0KGF4aXMkTURTMiwNCiAgICAgICAgICAgICAgICAgICBlbnZfY29yclssIGldLA0KICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJrZW5kYWxsIikNCiAgY29yX2F4MltpXSA8LSBjdC5pJGVzdGltYXRlDQogIHB2X2F4MltpXSA8LSBjdC5pJHAudmFsdWUNCn0NCg0KY29yX3RhYiA8LSBkYXRhLmZyYW1lKGVudiA9IG5hbWVzKGVudl9jb3JyKSwNCiAgICAgICAgICAgICAgICAgICAgICBvcmRfYXgxID0gY29yX2F4MSwNCiAgICAgICAgICAgICAgICAgICAgICBwdmFsX2F4MSA9IHB2X2F4MSwNCiAgICAgICAgICAgICAgICAgICAgICBvcmRfYXgyID0gY29yX2F4MiwNCiAgICAgICAgICAgICAgICAgICAgICBwdmFsX2F4MiA9IHB2X2F4MikNCg0KY29yX3RhYg0KDQp3cml0ZS5jc3YoeCA9IGNvcl90YWIsDQogICAgICAgICAgZmlsZSA9IGZpbGUucGF0aChkYXRhUGF0aCwiaW5wdXRzL05TY29yLXRhYmxlX3I2XzIwMHJlcF9NTEQtYmF0aHkuY3N2IiksDQogICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCiMjIyBEb3QgY2hhcnQgdG8gY2hlY2sgZm9yIGdhcHMgaW4gY29ycmVsYXRpb24NCg0KYGBge3J9DQpjb3JfYTFfc29ydDwtY29yX3RhYiU+JQ0KICBtdXRhdGUoYWJzX29yZF9heDE9YWJzKG9yZF9heDEpLA0KICAgICAgICAgYWJzX29yZF9heDI9YWJzKG9yZF9heDIpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGFic19vcmRfYXgxKSkNCg0KY29yX2EyX3NvcnQ8LWNvcl90YWIlPiUNCiAgbXV0YXRlKGFic19vcmRfYXgxPWFicyhvcmRfYXgxKSwNCiAgICAgICAgIGFic19vcmRfYXgyPWFicyhvcmRfYXgyKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhhYnNfb3JkX2F4MikpDQoNCmRvdGNoYXJ0KGNvcl9hMV9zb3J0JGFic19vcmRfYXgxLCBtYWluPSJBYnNvbHV0ZSAoKy8tKSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBlbnZWYXJzIGFuZCBnbm1kcyBheGlzIDEiKQ0KDQpjb3JfY3V0PC0wLjQgI2RlY2lkZQ0KDQpjb3Jfc2VsPC1zdWJzZXQoY29yX2ExX3NvcnQsYWJzX29yZF9heDE+Y29yX2N1dCkNCmNvcl9zZWwNCmBgYA0KDQoNCiMjIyBTZWwgZW52IHZhciAodG9wIGNvcnIpDQpgYGB7cn0NCmVudl9vcyA8LSBlbnZbLCBjb3Jfc2VsJGVudl0NCmVudl9vcw0Kc3RyKGVudl9vcykNCg0KYGBgDQoNCg0KIyMjIE9yZGlzdXJmcyB0b3AgY29ycg0KYGBge3J9DQpvcmRzcmZzIDwtIGxpc3QobGVuZ3RoID0gbmNvbChlbnZfb3MpKQ0KDQpmb3IgKGkgaW4gc2VxKG5jb2woZW52X29zKSkpIHsNCiAgb3MuaSA8LSBnZ19vcmRpc3VyZihvcmQgPSBvcmQsDQogICAgICAgICAgICAgICAgICAgICAgZW52LnZhciA9IGVudl9vc1ssIGldLA0KICAgICAgICAgICAgICAgICAgICAgIHB0LnNpemUgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICMgYmlud2lkdGggPSAwLjA1LA0KICAgICAgICAgICAgICAgICAgICAgIHZhci5sYWJlbCA9IG5hbWVzKGVudl9vcylbaV0sDQogICAgICAgICAgICAgICAgICAgICAgZ2VuLnRleHQuc2l6ZSA9IDEwLA0KICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLnRleHQuc2l6ZSA9IDE1LA0KICAgICAgICAgICAgICAgICAgICAgIGxlZy50ZXh0LnNpemUgPSAxMCkNCiAgDQogIG9yZHNyZnNbW2ldXSA8LSBvcy5pJHBsb3QNCn0NCg0Kb3Jkc3Jmc19wbHQgPC0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gb3Jkc3JmcywNCiAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMykNCg0Kb3Jkc3Jmc19wbHQNCmBgYA0KIyMjIyMgU2F2ZSBzb21lIG91dHB1dHMNCmBgYHtyfQ0KZ2dleHBvcnQob3Jkc3Jmc19wbHQsDQogICAgICAgICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoZGF0YVBhdGgsIm91dHB1dHMvTlNvcmRpc3VyZnNfdG9wX2NvcnIucG5nIiksDQogICAgICAgICAgd2lkdGggPSAxNTAwLA0KICAgICAgICAgIGhlaWdodCA9IDIwMDApDQoNCmBgYA0KDQoNCiMjIyBTZWwgZW52IHZhciAobWFudWFsKQ0KYGBge3J9DQplbnZfb3NfbSA8LSBlbnZbLGMoIlRtZWFuX1JvYmluc29uIiwgI3RvcCBjb3JyDQogICAgICAgICAgICAgICAgICAic2FsdF9tYXgiLCAjdG9wIGNvcnINCiAgICAgICAgICAgICAgICAgICJTbWF4X1JvYmluc29uIiwgI2NvbXBhcmlzb24gdG8gdG9wIGNvcnINCiAgICAgICAgICAgICAgICAgICJzd0RlbnNSb2JfYXZzIiwgI3RvcCBjb3JyDQogICAgICAgICAgICAgICAgICAjIkJPMjJfaWNlY292ZXJsdG1heF9zcyIsI3RvcCBjb3JyIGF4Mg0KICAgICAgICAgICAgICAgICAjICJCTzIyX2ljZWNvdmVybWVhbl9zcyIsI3RvcCBjb3JyDQogICAgICAgICAgICAgICAgICAiQk8yMl9kaXNzb3htZWFuX2JkbWVhbiIsI3RvcCBjb3JyDQogICAgICAgICAgICAgICAgICAjIkJPMjJfY2FyYm9ucGh5dG9sdG1pbl9iZG1lYW4iLCN0b3AgY29yciAtIG5vIGNsZWFyIGdyYWRpZW50IGluIG9yZGlzdXJmDQogICAgICAgICAgICAgICAgICAiQk8yMl9wcGx0bWluX3NzIiwgI3RvcCBjb3JyDQogICAgICAgICAgICAgICAgICAiWC55IiwgI2NvbXBhcmlzb24gdG8gWQ0KICAgICAgICAgICAgICAgICAgIlkiLCAjdG9wIGNvcnINCiAgICAgICAgICAgICAgICAgICJzcGRfc3RkIiwgI3RvcCBjb3JyIGF4MiAoYmxlbmRlZCBtb2RlbCkNCiAgICAgICAgICAgICAgICAgICJDU3Bkc2RfUm9iaW5zb24iLCAjY29tcGFyaXNvbiB0byB0b3AgY29yciBheDIgKGJsZW5kZWQgbW9kZWwpDQogICAgICAgICAgICAgICAgICAibXVkIiwgI2hpZ2hlc3Qgc2VkIHZhciBheDEgKyBjb3JyDQogICAgICAgICAgICAgICAgICAiZ3JhdmVsIiwjaGlnaGVzdCBzZWQgdmFyIGF4MSAtIGNvcnINCiAgICAgICAgICAgICAgICAgICJCTzIyX3NpbGljYXRlbHRtYXhfYmRtZWFuIiwgI2p1c3QgdW5kZXIgdG9wIGNvcnIgYXgxDQogICAgICAgICAgICAgICAgICAiYmF0aHkiICNpbnR1aXRpdmUgZm9yIGNvbXBhcmlzb25zDQogICAgICAgICAgICAgICAgKV0NCmVudl9vc19tDQpzdHIoZW52X29zX20pDQoNCmBgYA0KDQoNCiMjIyBPcmRpc3VyZnMgdG9wIGNvcnINCmBgYHtyfQ0Kb3Jkc3Jmc19tIDwtIGxpc3QobGVuZ3RoID0gbmNvbChlbnZfb3NfbSkpDQoNCmZvciAoaSBpbiBzZXEobmNvbChlbnZfb3NfbSkpKSB7DQogIG9zLmlfbSA8LSBnZ19vcmRpc3VyZihvcmQgPSBvcmQsDQogICAgICAgICAgICAgICAgICAgICAgZW52LnZhciA9IGVudl9vc19tWywgaV0sDQogICAgICAgICAgICAgICAgICAgICAgcHQuc2l6ZSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgIyBiaW53aWR0aCA9IDAuMDUsDQogICAgICAgICAgICAgICAgICAgICAgdmFyLmxhYmVsID0gbmFtZXMoZW52X29zX20pW2ldLA0KICAgICAgICAgICAgICAgICAgICAgIGdlbi50ZXh0LnNpemUgPSAxMCwNCiAgICAgICAgICAgICAgICAgICAgICB0aXRsZS50ZXh0LnNpemUgPSAxNSwNCiAgICAgICAgICAgICAgICAgICAgICBsZWcudGV4dC5zaXplID0gMTApDQogIA0KICBvcmRzcmZzX21bW2ldXSA8LSBvcy5pX20kcGxvdA0KfQ0KDQpvcmRzcmZzX3BsdF9tIDwtIGdnYXJyYW5nZShwbG90bGlzdCA9IG9yZHNyZnNfbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gNCkNCg0Kb3Jkc3Jmc19wbHRfbQ0KYGBgDQoNCiMjIyMjIFNhdmUgc29tZSBvdXRwdXRzDQpgYGB7cn0NCmdnZXhwb3J0KG9yZHNyZnNfcGx0X20sDQogICAgICAgICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoZGF0YVBhdGgsIm91dHB1dHMvTlNvcmRpc3VyZnNfbWFuX3NlbC5wbmciKSwNCiAgICAgICAgICB3aWR0aCA9IDIwMDAsDQogICAgICAgICAgaGVpZ2h0ID0gMjAwMCkNCg0KYGBgDQoNCg0KDQoNCiMjIyBFbnZmaXQNCmBgYHtyfQ0KIyMgU2VsZWN0IGlmIGFueSB2YXIgc2hvdWxkIGJlIGV4Y2x1ZGVkIGZyb20gZW52Zml0IChtYWtlcyBsZXNzIGJ1c3kgdG8gcmVhZCkNCmVudl9vc19tX2VudmZpdDwtZW52X29zX20gWyxjKCJUbWVhbl9Sb2JpbnNvbiIsICN0b3AgY29ycg0KICAgICAgICAgICAgICAgICAgInNhbHRfbWF4IiwgI3RvcCBjb3JyDQogICAgICAgICAgICAgICAgICAiU21heF9Sb2JpbnNvbiIsICNjb21wYXJpc29uIHRvIHRvcCBjb3JyDQogICAgICAgICAgICAgICAgICAic3dEZW5zUm9iX2F2cyIsICN0b3AgY29ycg0KICAgICAgICAgICAgICAgICMgICJCTzIyX2ljZWNvdmVybHRtYXhfc3MiLCN0b3AgY29yciBheDINCiAgICAgICAgICAgICAgICMgICAiQk8yMl9pY2Vjb3Zlcm1lYW5fc3MiLCN0b3AgY29ycg0KICAgICAgICAgICAgICAgICAgIkJPMjJfZGlzc294bWVhbl9iZG1lYW4iLCN0b3AgY29ycg0KICAgICAgICAgICAgICAgICAgIyJCTzIyX2NhcmJvbnBoeXRvbHRtaW5fYmRtZWFuIiwjdG9wIGNvcnIgLSBubyBjbGVhciBncmFkaWVudCBpbiBvcmRpc3VyZg0KICAgICAgICAgICAgICAgICMgICJCTzIyX3BwbHRtaW5fc3MiLCAjdG9wIGNvcnINCiAgICAgICAgICAgICAgICAgICJYLnkiLCAjY29tcGFyaXNvbiB0byBZDQogICAgICAgICAgICAgICAgICAiWSIsICN0b3AgY29ycg0KICAgICAgICAgICAgICAgICAjICJzcGRfc3RkIiwgI3RvcCBjb3JyIGF4MiAoYmxlbmRlZCBtb2RlbCkNCiAgICAgICAgICAgICAgICAgICJDU3Bkc2RfUm9iaW5zb24iLCAjY29tcGFyaXNvbiB0byB0b3AgY29yciBheDIgKGJsZW5kZWQgbW9kZWwpDQogICAgICAgICAgICAgICAgICAibXVkIiwgI2hpZ2hlc3Qgc2VkIHZhciBheDEgKyBjb3JyDQogICAgICAgICAgICAgICAgICAiZ3JhdmVsIiwjaGlnaGVzdCBzZWQgdmFyIGF4MSAtIGNvcnINCiAgICAgICAgICAgICAgICAgIyAiQk8yMl9zaWxpY2F0ZWx0bWF4X2JkbWVhbiIsICNqdXN0IHVuZGVyIHRvcCBjb3JyIGF4MQ0KICAgICAgICAgICAgICAgICAgImJhdGh5IiAjaW50dWl0aXZlIGZvciBjb21wYXJpc29ucw0KICAgICAgICAgICAgICAgIA0KICANCildDQoNCmNvbG5hbWVzKGVudl9vc19tX2VudmZpdCk8LWMoIlQiLCAjdG9wIGNvcnINCiAgICAgICAgICAgICAgICAgICJTbXgiLCAjdG9wIGNvcnINCiAgICAgICAgICAgICAgICAgICJTbWF4UiIsICNjb21wYXJpc29uIHRvIHRvcCBjb3JyDQogICAgICAgICAgICAgICAgICAic3dEZW5zUiIsICN0b3AgY29ycg0KICAgICAgICAgICAgICAgIyAgICJpY2Vjb3ZtYXgiLCN0b3AgY29yciBheDINCiAgICAgICAgICAgICAgICMgICAiaWNlY292YXYiLCN0b3AgY29ycg0KICAgICAgICAgICAgICAgICAgImRpc3NveGF2IiwjdG9wIGNvcnINCiAgICAgICAgICAgICAgICAgICMiQk8yMl9jYXJib25waHl0b2x0bWluX2JkbWVhbiIsI3RvcCBjb3JyIC0gbm8gY2xlYXIgZ3JhZGllbnQgaW4gb3JkaXN1cmYNCiAgICAgICAgICAgICAgICAjICAicHBsdG1pbiIsICN0b3AgY29ycg0KICAgICAgICAgICAgICAgICAgIlgiLCAjY29tcGFyaXNvbiB0byBZDQogICAgICAgICAgICAgICAgICAiWSIsICN0b3AgY29ycg0KICAgICAgICAgICAgICAgICAgIyJzcGRfc3RkIiwgI3RvcCBjb3JyIGF4MiAoYmxlbmRlZCBtb2RlbCkNCiAgICAgICAgICAgICAgICAgICJDU3Bkc2RSIiwgI2NvbXBhcmlzb24gdG8gdG9wIGNvcnIgYXgyIChibGVuZGVkIG1vZGVsKQ0KICAgICAgICAgICAgICAgICAgIm11ZCIsICNoaWdoZXN0IHNlZCB2YXIgYXgxICsgY29ycg0KICAgICAgICAgICAgICAgICAgImdyYXZlbCIsI2hpZ2hlc3Qgc2VkIHZhciBheDEgLSBjb3JyDQogICAgICAgICAgICAgICAgICMgIlNpTHRtYXgiLCAjanVzdCB1bmRlciB0b3AgY29yciBheDENCiAgICAgICAgICAgICAgICAgICJiYXRoeSIgI2ludHVpdGl2ZSBmb3IgY29tcGFyaXNvbnMNCiAgICAgICAgICAgICAgICAgKQ0KDQojIyBFbnZmb3QgcGxvdA0KZ2dfZW52Zml0KG9yZCA9IG9yZCwNCiAgICAgICAgICBlbnYgPSBlbnZfb3NfbV9lbnZmaXQsDQogICAgICAgICAgcHQuc2l6ZSA9IDEpDQoNCiMjIEVudmZpdCBhbmFseXNpcw0KDQplZiA8LSBlbnZmaXQob3JkID0gb3JkLA0KICAgICAgICAgICAgIGVudiA9IGVudl9vc19tX2VudmZpdCwNCiAgICAgICAgICAgICAjIG5hLnJtID0gVFJVRQ0KICAgICAgICAgICAgICkNCmVmREYgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMoZWYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXkgPSAidmVjdG9ycyIpKQ0KYGBgDQoNCiMjIyMjIFNhdmUgdGhlIHBsb3QNCmBgYHtyfQ0KZ2dzYXZlKGZpbGVuYW1lID0gZmlsZS5wYXRoKGRhdGFQYXRoLCJvdXRwdXRzL05TRW52Rml0X21hbl9zZWxfY2xuLnBuZyIpLA0KICAgICAgIGRldmljZSA9ICJwbmciLA0KICAgICAgIGRwaT0zMDAgKQ0KYGBgDQojIyMgQ2F0ZWdvcmljYWwgZW52VmFyIHZpc3VhbGlzZWQgb24gdGhlIG1kc3Bsb3RzDQoNCiMjIyMgdXNlIGRhdGFzZXQgd2l0aCBjYXRlZ29yaWNhbCB2YXIgaW5jbHVkZWQNCg0KYGBge3J9DQplbnZfdmlzPC1lbnYNCmVudl92aXMkZ25tZHMxIDwtIG90dV82JGdubWRzMQ0KZW52X3ZpcyRnbm1kczIgPC0gb3R1XzYkZ25tZHMyDQpgYGANCg0KIyMjIyBnbm1kcyB3IG1sZCBtZWFuIC0gYmF0aHkNCmBgYHtyfQ0KcF9tbGQgPC0gZ2dwbG90KGRhdGEgPSBlbnZfdmlzLA0KICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBnbm1kczEsDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGdubWRzMikpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZml4ZWQoKSArDQogIGdndGl0bGUoIkdOTURTIGNvbG91cmVkIGJ5IHByb3hpbWl0eSB0byBtaXhlZCBsYXllciBkZXB0aCIsDQogICAgICAgICAgc3VidGl0bGUgPSAiRmlyc3QgcnVuIikgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBNTERtZWFuX2JhdGh5KSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAibGlnaHRncmF5IikgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAibGlnaHRncmF5IikNCg0KcF9tbGQNCmBgYA0KIyMjIyMgU2F2ZSB0aGUgcGxvdA0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSBmaWxlLnBhdGgoZGF0YVBhdGgsIm91dHB1dHMvTlNnbm1kc19NTERtZWFuQmF0aHkucG5nIiksDQogICAgICAgZGV2aWNlID0gInBuZyIsDQogICAgICAgZHBpPTMwMCApDQpgYGANCiMjIyMgZ25tZHMgdyBzZWRjbGFzcw0KIyMjIyMgZGVhbCB3aXRoIHNlZGNsYXNzIGNvZGVzDQpgYGB7cn0NCmVudl92aXM8LSBlbnZfdmlzICU+JSANCiAgbXV0YXRlKA0KICAgIHNlZGNsYXNzTmFtZSA9IGNhc2Vfd2hlbigNCiAgICAgICAgICAgIHNlZGNsYXNzID09ICIxIiB+ICJTZWRDb3ZlclIiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjUiIH4gIlJvY2siLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjIwIiB+ICJNdWQiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjIxIiB+ICJNd0Jsb2NrIiwNCiAgICAgICAgICAgIHNlZGNsYXNzID09ICI0MCIgfiAic011ZCIsDQogICAgICAgICAgICBzZWRjbGFzcyA9PSAiODAiIH4gIm1TYW5kIiwNCiAgICAgICAgICAgIHNlZGNsYXNzID09ICIxMDAiIH4gIlNhbmQiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjExMCIgfiAiZ011ZCIsDQogICAgICAgICAgICBzZWRjbGFzcyA9PSAiMTE1IiB+ICJnc011ZCIsDQogICAgICAgICAgICBzZWRjbGFzcyA9PSAiMTIwIiB+ICJnbVNhbmQiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjEzMCIgfiAiZ1NhbmQiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjE1MCIgfiAiTVNHIiwNCiAgICAgICAgICAgIHNlZGNsYXNzID09ICIxNjAiIH4gInNHcmF2ZWwiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjE3MCIgfiAiR3JhdmVsIiwNCiAgICAgICAgICAgIHNlZGNsYXNzID09ICIxNzUiIH4gIkdyYXZCbG9jayIsDQogICAgICAgICAgICBzZWRjbGFzcyA9PSAiMTg1IiB+ICJTR0JtaXgiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjIwNSIgfiAiUy9Nd0IiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjIwNiIgfiAiUy9Nd0cvQiIsDQogICAgICAgICAgICBzZWRjbGFzcyA9PSAiMjE1IiB+ICJTR0JhbHQiLA0KICAgICAgICAgICAgc2VkY2xhc3MgPT0gIjMwMCIgfiAiSGFyZFNlZCIsDQogICAgICAgICAgICBzZWRjbGFzcyA9PSAiNTAwIiB+ICJCaW9nZW5pYyINCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICkNCiAgKQ0KYGBgDQoNCiMjIyMjIyBjb2xvdXIgcGFsZXR0ZSB0byBjb3BlIHdpdGggdXAgdG8gMjUgY2F0ZWdvcmljYWwgY29sb3Vycw0KYGBge3J9DQpjMjUgPC0gYygNCiAgImRvZGdlcmJsdWUyIiwgIiNFMzFBMUMiLCAjIHJlZA0KICAiZ3JlZW40IiwNCiAgIiM2QTNEOUEiLCAjIHB1cnBsZQ0KICAiI0ZGN0YwMCIsICMgb3JhbmdlDQogICJibGFjayIsICJnb2xkMSIsDQogICJza3libHVlMiIsICIjRkI5QTk5IiwgIyBsdCBwaW5rDQogICJwYWxlZ3JlZW4yIiwNCiAgIiNDQUIyRDYiLCAjIGx0IHB1cnBsZQ0KICAiI0ZEQkY2RiIsICMgbHQgb3JhbmdlDQogICJncmF5NzAiLCAia2hha2kyIiwNCiAgIm1hcm9vbiIsICJvcmNoaWQxIiwgImRlZXBwaW5rMSIsICJibHVlMSIsICJzdGVlbGJsdWU0IiwNCiAgImRhcmt0dXJxdW9pc2UiLCAiZ3JlZW4xIiwgInllbGxvdzQiLCAieWVsbG93MyIsDQogICJkYXJrb3JhbmdlNCIsICJicm93biINCikNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCg0KcF9zZWQgPC0gZ2dwbG90KGRhdGEgPSBlbnZfdmlzLA0KICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBnbm1kczEsDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGdubWRzMikpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZml4ZWQoKSArDQogIGdndGl0bGUoIkdOTURTIGNvbG91cmVkIGJ5IHNlZGltZW50IGNsYXNzIiwNCiAgICAgICAgICBzdWJ0aXRsZSA9ICJGaXJzdCBydW4iKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGZhY3RvcihzZWRjbGFzc05hbWUpKSkgKw0KICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YzI1KSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsDQogICAgICAgICAgICAgY29sb3VyID0gImxpZ2h0Z3JheSIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsDQogICAgICAgICAgICAgY29sb3VyID0gImxpZ2h0Z3JheSIpKw0KICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChuY29sPTIpKQ0KDQpwX3NlZA0KYGBgDQojIyMjIyBTYXZlIHRoZSBwbG90DQpgYGB7cn0NCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGUucGF0aChkYXRhUGF0aCwib3V0cHV0cy9OU2dubWRzX3NlZGNsYXNzLnBuZyIpLA0KICAgICAgIGRldmljZSA9ICJwbmciLA0KICAgICAgIGRwaT0zMDAgKQ0KYGBgDQojIyMjIGdubWRzIHcgbGFuc2NhcGUNCiMjIyMjIGRlYWwgd2l0aCBzZWRjbGFzcyBjb2Rlcw0KYGBge3J9DQplbnZfdmlzPC0gZW52X3ZpcyAlPiUgDQogIG11dGF0ZSgNCiAgICBsYW5kc2NhcGVOYW1lID0gY2FzZV93aGVuKA0KICAgICAgICAgICAgbGFuZHNjYXBlID09ICIxIiB+ICJTdHJhbmRmbGF0IiwNCiAgICAgICAgICAgIGxhbmRzY2FwZSA9PSAiMjEiIH4gIkNvbnRTbG9wZSIsDQogICAgICAgICAgICBsYW5kc2NhcGUgPT0gIjIyIiB+ICJDYW55b24iLA0KICAgICAgICAgICAgbGFuZHNjYXBlID09ICIzMSIgfiAiVmFsbGV5IiwNCiAgICAgICAgICAgIGxhbmRzY2FwZSA9PSAiMzIiIH4gIkZqb3JkIiwNCiAgICAgICAgICAgIGxhbmRzY2FwZSA9PSAiNDEiIH4gIkRlZXBQbGFpbiIsDQogICAgICAgICAgICBsYW5kc2NhcGUgPT0gIjQyIiB+ICJTbG9wZVBsYWluIiwNCiAgICAgICAgICAgIGxhbmRzY2FwZSA9PSAiNDMiIH4gIlNoZWxmUGxhaW4iLA0KICAgICAgICAgICAgbGFuZHNjYXBlID09ICI0MzEiIH4gInNoYWxsb3dWYWxsZXkiDQogICAgKQ0KICApDQpgYGANCg0KDQpgYGB7cn0NCg0KcF9sYW5kIDwtIGdncGxvdChkYXRhID0gZW52X3ZpcywNCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gZ25tZHMxLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBnbm1kczIpKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZpeGVkKCkgKw0KICBnZ3RpdGxlKCJHTk1EUyBjb2xvdXJlZCBieSBsYW5kc2NhcGUgY2xhc3MiLA0KICAgICAgICAgIHN1YnRpdGxlID0gIkZpcnN0IHJ1biIpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gZmFjdG9yKGxhbmRzY2FwZU5hbWUpKSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAibGlnaHRncmF5IikgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwNCiAgICAgICAgICAgICBjb2xvdXIgPSAibGlnaHRncmF5IikrDQogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5jb2w9MikpDQoNCnBfbGFuZA0KYGBgDQojIyMjIyBTYXZlIHRoZSBwbG90DQpgYGB7cn0NCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGUucGF0aChkYXRhUGF0aCwib3V0cHV0cy9OU2dubWRzX2xhbmRzY2FwZS5wbmciKSwNCiAgICAgICBkZXZpY2UgPSAicG5nIiwNCiAgICAgICBkcGk9MzAwICkNCmBgYA0KDQojIyMjIEdubWRzIHcgZ21vcnBoDQpgYGB7cn0NCg0KcF9nbW8gPC0gZ2dwbG90KGRhdGEgPSBlbnZfdmlzLA0KICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBnbm1kczEsDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGdubWRzMikpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZml4ZWQoKSArDQogIGdndGl0bGUoIkdOTURTIGNvbG91cmVkIGJ5IGxhbmRzY2FwZSBjbGFzcyIsDQogICAgICAgICAgc3VidGl0bGUgPSAiRmlyc3QgcnVuIikgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBmYWN0b3IoZ21vcnBoKSkpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsDQogICAgICAgICAgICAgY29sb3VyID0gImxpZ2h0Z3JheSIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsDQogICAgICAgICAgICAgY29sb3VyID0gImxpZ2h0Z3JheSIpKw0KICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChuY29sPTIpKQ0KDQpwX2dtbw0KYGBgDQojIyMjIyBTYXZlIHRoZSBwbG90DQpgYGB7cn0NCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGUucGF0aChkYXRhUGF0aCwib3V0cHV0cy9OU2dubWRzX2dtb3JwaC5wbmciKSwNCiAgICAgICBkZXZpY2UgPSAicG5nIiwNCiAgICAgICBkcGk9MzAwICkNCmBgYA0KDQpgYGB7cn0NCmNhdF92YXJfcGxvdHM8LXBfbWxkK3Bfc2VkK3BfbGFuZCtwX2dtbw0KYGBgDQojIyMjIyBTYXZlIHRoZSBwbG90DQpgYGB7cn0NCmdnZXhwb3J0KGNhdF92YXJfcGxvdHMsDQogICAgICAgICAgZmlsZW5hbWUgPSBmaWxlLnBhdGgoZGF0YVBhdGgsIm91dHB1dHMvTlNnbm1kc19jYXR2YXIucG5nIiksDQogICAgICAgICAgd2lkdGggPSAxMDAwLA0KICAgICAgICAgIGhlaWdodCA9IDgwMCkNCmBgYA0KDQojIyMjIFNhbXBsZSBpZGVudGlmaWNhdGlvbiBpbiB0aGUgbWRzcGxvdA0KDQpgYGB7cn0NCnBfZ21vIDwtIGdncGxvdChkYXRhID0gZW52X3ZpcywNCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gZ25tZHMxLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBnbm1kczIpKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZpeGVkKCkgKw0KICBnZ3RpdGxlKCJHTk1EUyBjb2xvdXJlZCBieSBsYW5kc2NhcGUgY2xhc3MiLA0KICAgICAgICAgIHN1YnRpdGxlID0gIkZpcnN0IHJ1biIpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gZmFjdG9yKFNhbXBJRCkpKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsDQogICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgIGNvbG91ciA9ICJsaWdodGdyYXkiKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsDQogICAgICAgICAgICAgbGluZXR5cGUgPSAyLA0KICAgICAgICAgICAgIGNvbG91ciA9ICJsaWdodGdyYXkiKSsNCiAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2l6ZT1GQUxTRSkNCg0KZ2dwbG90bHkocF9nbW8pDQpgYGANCg0KIyMgSW50ZXJhY3RpdmUgRGVucyBvcmRpc3VyZg0KDQoNCmBgYHtyfQ0KDQoNClQubWRzPC0gZ2dwbG90KGRhdGEgPSBlbnZfdmlzLA0KICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBnbm1kczEsDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGdubWRzMikpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gc3dEZW5zUm9iX2F2cyksDQogICAgICAgICAgICAgc2l6ZSA9IDEpICsNCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihsaW1pdHMgPSBjKDEwMjcuNSwgMTA0MC43KSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9ycz1jKCdyZWQnLCd5ZWxsb3cnLCdncmVlbicpKSsNCiAgZ2d0aXRsZSgiR25tZHMgY29sb3VyZWQgYnkgZGVucyAoTlMpIikNCg0KDQpnZ3Bsb3RseShULm1kcykNCmBgYA0KDQoNCiMjIyBWaXMgcHJvcG9zZWQgVGhyZXNob2xkDQpgYGB7cn0NCg0KZW52X3ZpcyRkZW5zVGhyZXNoPC1jdXQoZW52X3N1Yl9tZXRhJHN3RGVuc1JvYl9hdnMsIA0KICAgICAgYnJlYWtzPWMoMTAyOCwxMDMxLjMsMTA0MSksDQogICAgICBsYWJlbHM9YygiTG9EZW5zIiwiSGlEZW5zIikpDQoNClRoLm1kczwtIGdncGxvdChkYXRhID0gZW52X3ZpcywNCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gZ25tZHMxLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBnbm1kczIpKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGRlbnNUaHJlc2gpLA0KICAgICAgICAgICAgIHNpemUgPSAxKSArDQogIyBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jYlBhbGV0dGUpICsjIG5vbi1vcmRlcmVkIGNvbG91cmJsaW5kIHBhbGxldHRlDQogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKyAjIG9yZGVyZWQgY29sb3VyYmxpbmQgcGFsbGV0dGUNCiAgZ2d0aXRsZSgiZ25tZHMgY29sb3VyZWQgYnkgY2F0ZWdvcmljYWwgZGVucyB0aHJlc2hvbGRzIikNCg0KDQpwbG90KFRoLm1kcykNCmBgYA0KIyMjIyMgU2F2ZSB0aGUgcGxvdA0KYGBge3J9DQpnZ3NhdmUoZmlsZW5hbWUgPSBmaWxlLnBhdGgoZGF0YVBhdGgsIm91dHB1dHMvTlNnbm1kc19kZW5zVGhyZXNoMTAzMV8zLnBuZyIpLA0KICAgICAgIGRldmljZSA9ICJwbmciLA0KICAgICAgIGRwaT0zMDAgKQ0KYGBgDQoNCg0KDQojIyMgRG90cGxvdCB0ZW1wZXJhdHVyZQ0KDQpgYGB7cn0NCmRvdGNoYXJ0KHNvcnQoZW52X3ZpcyRzd0RlbnNSb2JfYXZzKSwgbWFpbj0iRG90Y2hhcnQgb2YgZGVucyBhdCBOb3JsYW5kIFNsb3BlIikNCmBgYA0KDQojIyMgRG90cGxvdCB6b29tZWQgb24gMi00KkMNCmBgYHtyfQ0KZG90Y2hhcnQoc29ydChlbnZfdmlzJHN3RGVuc1JvYl9hdnMpLCB4bGltPWMoMTAzMSwxMDMyKSxtYWluPSJEb3RjaGFydCBvZiBkZW5zIGJldHdlZW4gMTAzMSBhbmQgMTAzMiBhdCBOb3JsYW5kIFNsb3BlIikNCmBgYA==